'ls -1': dosya adlarının uzantısı olmadan listelenmesi


24

ls -1 elemanlarımı şöyle listeler:

foo.png
bar.png
foobar.png
...

Ben böyle olmadan listelenen .pngistiyorum:

foo
bar
foobar
...

(dir sadece .pngdosya içeriyor )

Birisi bana grepbu durumda nasıl kullanılacağını söyleyebilir mi?

Amaç: Uzantı olmadan tüm adların listelendiği bir metin dosyasına sahibim. Hangi dosyayı eksik olduğunu görmek için metin dosyasını klasörle karşılaştıran bir komut dosyası yapmak istiyorum.


36
Böyle bir talebe dikkat etmek istiyorsun. Linux'un dosya adı uzantısı yoktur. Linux'ta içeriklerini içerebilen veya içermeyen dosya isimleri vardır .. Kongre .pngsonunda dosyalarınızı isimlendirmesini söylese de, foo.zipya my.picture.20160518da sadece ya da png dosyalarına sahip olamamam için hiçbir neden yok mypic.
hymie

2
@ hymie biliyorum, ancak bu klasördeki öğelerimin tümü sonunda .png ile adlandırılıyor.
Colin,

14
"Uzantı" nedir? Bu Unix dosya adının bir parçası değil; her neyse VMS / NT / Windows’tan bir ürün. Siz gençler de bahçemden iniyorsunuz. :)
mpez0

28
Bunu abartmayalım. İşletim sistemi uzantıları sadece dosya adının bir parçası olarak kabul eder, ancak birçok unix programı derleyiciden GUI'ye dikkat eder. Bu kavram kesinlikle unix'e yabancı değil.
alexis,

1
Genellikle çıktının ayrıştırılmasından kaçınılması ve çıktısının ayrıştırılmasından kaçınılmasılsls ve findçoğunlukla newlinedosya adında sekme karakterinin ortaya çıkması nedeniyle önerilmektedir . Dosya adı The new art of working on .png\NEWLINE files and other formatsönerilen çözümün çoğu ise sorun yaratacaktır.
Hastur

Yanıtlar:


41

Bu iş için sadece kabuğa ihtiyacınız var.

POSIXly:

for f in *.png; do
    printf '%s\n' "${f%.png}"
done

İle zsh:

print -rl -- *.png(:r)

4
Buna gerek yok printf; echo ${f%.png}yeterli olacaktır.
David Conrad

11
@ Conrad: echo kullanımı, bazı durumlarda dosya adı çizgi ile başlıyorsa veya çıkış dizileri içeriyorsa, düzgün çalışmaz.
cuonglm

3
@DavidConrad: Ayrıca bakınız unix.stackexchange.com/a/65819/38906
cuonglm

35
ls -1 | sed -e 's/\.png$//'

sedKomut kaldırır herhangi bir dize (, o boş dize ile değiştirir) .pngbulunan uca bir dosya adı.

.Olarak kaçan edilir \.o tarafından yorumlanır, böylece sedbir hazır olarak .karakteri yerine regexp .(vasıta herhangi bir karakteri eşleştirmek olan). $Eşleşmezse yüzden, sonu hattı çapa olan .pngbir dosya ortasında.


4
Ben OP istiyor herhangi muhtemelen soyulmuş uzantısı, ancak yalnızca "sonuncusu". Öyleyse belki de iyi cevabınızı şu şekilde değiştirin:sed 's/\.[^.]*$//'
Otheus

1
evet, bu regexp'in bu durumda çalışacak ... ama OP o istiyorsa, derler bu yüzden yerine özellikle bunların ".png olmadan listelenen istiyoruz" diyerek
cas

4
-1Burada varsayılan olmak gerekli değildir.
jlliagre

3
@jlliagre Ben -1belirtilmesi gereken cas ile katılıyorum . Sadece boru açıldığında, bazıları için gizli bir sürpriz olan, varsayılan ayardır. Bu yüzden onu açık bir hale getirmek, anlaşmaya yardımcı olur. Bunu komut dosyalarımda da yapıyorum, böylece ne tür bir çıktı beklediğimi biliyorum.
Otheus

1
Uyarı.png Bir newline karakterinden önce ( ) tuşuyla bir dosya adı olması durumunda, .pngyalnızca sonuncuyu değil, onu bile sileceksiniz . Ls'nin çıktısını toplamaktan ve ayrıştırmaktan kaçınmak daha iyidir, çoğu zaman iyi gizlenmiş sürprizler saklı tutar ...
Hastur

16

Sadece bash kullanmak istiyorsanız:

for i in *; do echo "${i%.png}"; done

grepKibrit bulmaya çalışırken ulaşmanız gerekir , bunun için seduygun olanı çıkarmak / değiştirmek yerine :

find . -maxdepth 1 -name "*.png"  | sed 's/\.png$//'

PNG dosyalarınızda düzen getirmek için bazı alt dizinler oluşturmanız gerektiğine karar verdikten sonra bunu kolayca değiştirebilirsiniz:

find . -name "*.png"  | sed 's/\.png$//'

ls -1 | sed 's / .png //' harika çalışıyor. Teşekkür ederim!
Colin

find Borulu için sedsize anahtarla (bir dosyayı bulursanız çözümü bazı sorunları sunabilirsiniz .pngadının bir parçası olarak ve sadece satır karakteri önce). Çıktısını borulamaktan ve ayrıştırmaktan kaçınmak daha iyidir, findveya lsgenellikle iyi gizlenmiş sürprizleri saklı tutar ... (bazı kelimeler ve cevaplar cevaplarda daha fazla).
Hastur

Muhtemelen son örnekte olduğu findgibi bir şeyle değiştirin echo. Açık değil ne amaçla findorada hizmet veren ve sonuçları dizin yapısı bağlıdır (yani bir dizin varsa files.png)

@BroSlow Daha mantıklı bir şey için güncellendi.
Anthon

13

Ben gitmek istiyorum basename(GNU uygulanmasını varsayarak):

basename --suffix=.png -- *.png

Bir boruda kullanmak istiyorsanız, NUL ile ayrılmış (yeni satırla ayrılmış) çıktı üretmek için GNU ana adının -z(veya --zero) seçeneğini kullanmayı yararlı bulabileceğinizi unutmayın .
Toby Speight

11

Bir başka çok benzer cevap (Bu özel varyantın henüz ortaya çıkmamasına şaşırdım):

ls | sed -n 's/\.png$//p'
  • Bu -1seçeneğe ihtiyacınız yoktur ls, çünkü lsstandart çıktının bir terminal olmadığını varsayalım (bu bir boru, bu durumda).
  • -nseçeneği sed'varsayılan olarak çizgi baskı yok' yollarla
  • /pikame araçlarının sonunda opsiyon 'bir değişimin yapıldığı takdirde ... ve bu satırı yazdırmak'.

Bunun net etkisi ise uç yalnızca bu satırları yazdırmak için .pngbirlikte .pngkaldırılan. Yani, bu aynı zamanda OP'nin sorusunun hafif genellemesine de dayanıyor, burada dizin sadece .pngdosyalar içermiyor .

sed -nEğer aksi sed + grep kullanabilir nereye teknik vakalarda sıklıkla yararlıdır.


Cevabınızı yazarken gösterdiğiniz özen hoşuma gidiyor. Bu çözüm yeni satırlar da dahil olmak üzere dosya adlarıyla ilgili sorunlar sunacak , adın ilk bölümünü basmayacak . Dahası .png, newline karakterinden önce ( ) tuşu olan daha nemli ise: bu durumda png olmadan sadece son kısmı silmeyeceksiniz. Çıktının ayrıştırılmasından (ve kullanılmasından) kaçınılması genellikle önerilmektedir, lsçünkü sorunlar sadece düşünmediğiniz yerlere gizlenebilmektedir ...
Hastur

2
@Hastur Prensipte haklısınız ve ayrıştırma konusundaki ünlü sayfa, patolojik dosya adlarını verirken daha fazla sorun (ve çözüm) listeler. Fakat en iyi kullanım şekli, patolojik dosya adlarına sahip olmamaktır (doh!); ve bunu yapamıyorsanız veya eğer gerekir onlara karşı sağlam olması, o zaman birini kullanın findveya - muhtemelen daha iyi - daha güçlü bir dil kullanmak daha sh(aslında onları yönetmek için sh olabilir en iyi seçimdir içinde olduğu anlamına gelmez her şeyi her vaka). Kabuk önce kullanılabilirlik için tasarlanmıştır.
Norman Gray

Prensip olarak, kullanılabilirlik konusunda hemfikirim, ancak bu değişken her yeni satırda bir dosya adınız olduğunda başarısız oluyor . Bu, örneğin bir GUI'deki bir pdf'den bir satırı kopyalayıp yapıştırdığınızda, kolayca fark edilmeden gerçekleşebilir. Dolayısıyla, yalnızca patolojik dosya adlarından kaçınılması gerektiğini düşünürsünüz .
Hastur

Üstelik IMHO Ayrıştırmaya başlamak kolaydır ls, ancak gelecekteki sorunların bir yanıdır. Genellikle daha sonra kullanacağımız senaryoları yaparız, sınırlarını çoktan unutursak ... (insan, her zamanki gibi). Daha iyi görsem bile (saf kabuklu) cuonglm bir , sağlam ve posix uyumlu bir cevap versem bile bir örnek önerdimfind ( -execpipo ile ve piposuz ) .
Hastur

@Hastur: Bu gelecekteki sorunlar yine de ortaya çıkacak. Sistemdeki birçok şey, yeni hatları olan dosyalara karşı sağlam değildir. Örneğin, kullanmayı locateveya makeüzerlerini kullanmayı deneyin .
reinierpost

8

Bunu yapmak için yalnızca BASH komutlarını kullanabilirsiniz (herhangi bir harici araç olmadan).

for file in *; do echo "${file%.*}"; done 

Bu, / usr / bin olmadığınızda ve this.is.image.png gibi dosya adları ve tüm uzantılar için iyi çalıştığında faydalıdır.


6

Ayrıştırmak lsveya borulamak güvenli değildir find[ 1 , 2 ]

Ayrıştırmak için güvenli (ve boruya) çıktısı değil lsya findmümkün bulmak başlıca nedeni, dosya adları olmayan olağan karakterlerin yeni satır , sekme ... İşte saf kabuk döngüsü çalışacak [ cuonglm ] .
Hatta findkomut borulu değil seçeneğiyle -execçalışacaktır:

find ./*.png  -exec  basename {} .png  \;

Güncellemeler / Notlar : find .Gizli dosyaları bile aramak veya find ./*.pngyalnızca gizli olmayanları bulmak için kullanabilirsiniz. Bulunacak seçenek bir seçenek olarak alacağı için find *.png -exec ...adında bir dosya bulunması durumunda sorun yaşayabilirsiniz .png. Olarak -maxdepth 0adlandırılan dizinlerde Dir_01.pngveya find ./*.png -prune -exec ...maxdepth'e izin verilmediğinde aşağı inmeyi önlemek için ekleyebilirsiniz (teşekkürler Stéphane). Bu dizinleri listelemekten kaçınmak istiyorsanız, seçeneği eklemelisiniz -type f(normal olmayan dosyaların diğer türlerini de hariç tutacaktır). manKullanılabilir tüm seçenekler hakkında daha eksiksiz bir panorama için bir göz atın ve daha iyi bir taşınabilirlik için POSIX uyumlu olduklarını kontrol etmeyi unutmayın.

Bazı kelimeler daha

Örneğin, başlığın bir belgeden kopyalanması ve dosya adına yapıştırılması, bir veya daha fazla yeni satırın dosya adının kendisinde bitmesi olabilir. Yeni bir satırdan hemen önce kullanmak zorunda olduğumuz anahtarı bile bir başlığın içerebileceği kadar şanssız bile olabiliriz:

The new art of working on .png
files and other formats.

Test etmek istiyorsanız, komutlarla bunun gibi dosya adları oluşturabilirsiniz.

touch "A file with two lines"$'\n'"and This is the second.png"
touch "The new art of working on .png"$'\n'"files and other formats.png"

Yazdırılamayan karakterler yerine basit /bin/ls *pngçıktılar?

A file with two lines?and This is the second.png
The new art of working on .png?files and other formats.png

Hangi olacak tüm durumlarda çıkış borusu arasında lsveya findaşağıdaki komutu mevcut satır Yeni geliyorsa anlamak hiçbir ipucu olacaktır dosya adı ya da bir takip ederse yeni satır emsal karakteri dosya adı . Bir kötü gerçekten adı, ama yine de yasal bir.

Bir kabuk parametresi-Genişleme olan bir kabuk döngüsü, ${parameter%word}, varyant hem de printfveya echoçalışır [ cuonglm ], [ Anthon1 ] .

for f in *.png; do printf "%s\n" "${f%.png}" ; done

Shell Parametre Expansion [ 3 ] man sayfasından

$ {parametre% word}
$ {parametre %% word}

... genişlemenin sonucu, silinen en kısa eşleştirme modeline ('%' vaka) veya en uzun eşleme modeline ('%%' durum) ilişkin parametre değeridir.


Ayrıca findkomutunuzun sonuçları bir bit değişkenidir (örneğin, bir dizin varsa files.png)

1
Sevgili @BroSlow, yukarıdaki cevabı yazdığımda, o andaki diğer değişkenlerin 13 (tümünü) komut satırına göre bir komut dosyasında kabuk çağırma argümanı olarak başlattım. Lütfen aynısını yapın ve beklediğiniz gibi davranıp davranmadıklarını söyleyin. Testlerimi bash 4.3.11, 0.5.7-4, zsh (gerektiğinde) 5.0.2 ile yaptım . Okumak serbest hissedin Bu yayını bir şey daha ekler. Ben nota hakkında hemfikir boru çıktısını findbu ben için, açıkça önerdi-exec ve ben başlığında yazdım. :-).
Hastur

Vikiyi tekrar okudum. Hala örneğinizde boruya ihtiyacınız olduğunu düşünüyorum, çünkü burada tartışılan şey bu. Ve modern versiyonların çoğunluğu için, lsçıktı aktarılırken veya yönlendirilirken herhangi bir sorun yoktur, ancak wiki'de belirtildiği gibi herkes için işe yaramayabilir. Çoğu ?, çıkış terminale gönderildiğinde yalnızca özel karakterlerin yerine yerleştirir . yani, Yap echo *.png | od -cve ls *.png | od -c. Newline sorunu, lsborunun her iki tarafında da sonlandırılmayan herhangi bir komutla ilgili bir sorun değildir.

1
printf "${f%.png}\n"Hata. İlk argüman formattır, burada değişken verileri kullanmamalısınız. DoS güvenlik açığı olarak da görülebilir ( %1000000000s.pngörneğin bir dosyayla deneyin ).
Stéphane Chazelas

İhtiyacınız olacak find ./*.png -prune -exec...ya da dosya isimlerinde -(ve dizin tipi dosyalarda -maxdepthtaşınabilir olmadığına dikkat edin )
sorun yaşanacaktır

4

yetmedi mi

ls -1 | sed 's/\.png//g'

veya genel olarak, bu

ls -1 | sed 's/\.[a-z]*//g'

tüm uzantıları kaldıracak


Öyleydi ama diğer çözümler de işe yarıyor.
Colin,

Demek istediğim, sorunuz -1 ile başladı, yani -1 bunu yapmalı. :)
Rohail Abbas

-1Burada varsayılan olmak gerekli değildir.
jlliagre

@Rohail Abbas Ama her sistem sed yüklü değil mi?
Colin,

1
Nitekim, ancak lsyine de, çıktısı bir terminal olmadığında bu seçenek olmadan yapar, buradaki durum budur.
jlliagre

3

Kullanım rev:

ls -1 | rev | cut -f 2- -d "." | rev

revtüm dizeleri (satırları) ters çevirir; ilk '' den sonra her şeyi kesersin. ve rev, kalanı tekrar tersine çevirir.

Eğer grep' almak ' istiyorsanız :

ls -1 | rev | cut -f 2- -d "." | rev | grep 'alma'

-1Burada varsayılan olmak gerekli değildir.
jlliagre

2
Bu adında bir dosya üzerinde kötü başarısızMy.2016.Summer.Vacation.png
David Conrad

@DavidConrad benim hatam: / Düzeltdimcut -f 2-
Tom Solid '

Şimdi bu dosyayla çalışıyor, ancak henüz bir dosyayla değil .pngve hemen ardından bir yeni satırla ... Ayrıştırmaktan kaçınılması öneriliyor, lsçünkü sürprizleri iyi gizlemeyi seviyor ... :-)
Hastur

2

Dizinin yalnızca uzantı olarak .png dosyası olduğunu bilseydim, şunu çalıştırırdım: ls | awk -F. '{print $1}'

Bu, dosya adı.extension olan herhangi bir şey için ilk "alanını" döndürür.

Örnek:

[rsingh@rule51 TESTDIR]$ ls
10.png  1.png  2.png  3.png  4.png  5.png  6.png  7.png  8.png  9.png

[rsingh@rule51 TESTDIR]$ ls | awk -F. '{print $1}'
10
1
2
3
4
5
6
7
8
9

Ne yazık ki , birden fazla olan tüm dosya adlarında. , Image.1.pnghatta içinde güzel karakter olmayan , içinde özel karakter bulunanlarda bile başarısız olacaktır . yeni satır veya içinde (giriş) kaydı ayırıcı olarak kullanacağı biri olarak awk, RS. lsÇıktının ayrıştırılmasından kaçınılması önerilir, çünkü beklemeyeceğiniz zaman ortaya çıkacak problemi gizlemeyi sever. Bu referans 1 veya 2'de daha fazla okuyabilirsiniz . Btw awk kullanma fikri güzel ... bir cevapta bazı örnekler koydum.
Hastur

Doğru, ancak Colin tarafından sağlanan örnek göz önüne alındığında, iyi işe yarayacak. Önerdiğiniz dava için çalışmasını sağlamak için, muhtemelen şunu değiştiririm: [rsingh @ rule51 TESTDIR] $ ls | sed -e 's / .png $ //' 10 1 2 3 4 5 6 7 8 9 harry.the.bunny whats.a.png.filename Zor olmaya çalışmıyorum ama Colin’in ihtiyacı olduğuna emin değilim sorunun ne olacağını ayrıştırıyor.
16'da

üzgünüm ... sadece 'ls' çıktısını değiştirmeden önce dosyaları içeren dizini göstermediğimi fark ettim [rsingh @ rule51 TESTDIR] $ ls 10.png 2.png 4.png 6.png 8.png harry.the.bunny.png 1.png 3.png 5.png 7.png 9.png whats.a.png.filename.png [rsingh @ rule51 TESTDIR] $ ls | sed -e 's / .png $ //' 10 1 2 3 4 5 6 7 8 9 harry.the.bunny whats.a.png.filename
rsingh

not1. içinde \.içeriden kaçmanız gerekir sed -e 's/\.png$//', ancak bu yüzden yeni yazılmış bir cevap haline gelir. :-( note2awk gibi bir şeyle kullanmayı deneyebilirsiniz ls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}'... ama satırın gelip gelmediğini her zaman awk'nin bilmeyeceği bir problemle karşılaşacaksınız, dosya adının içinde bir satırsonu mu yoksa yeni bir satır mı yoksa. .
Hastur

Teşekkürler Hastur, bunu özledim :). Ayrıca, bu durumda awk kullanımını sed lehine çevirdim.
rsingh

2

"yorumuna göre," Tüm adların uzantı olmadan listelendiği bir metin dosyasına sahibim. Hangi dosyayı eksik olduğunu görmek için metin dosyasını klasörle karşılaştıran bir PHP betiği yapmak istiyorum ":

for file in $(cat yourlist) ; do
  [ -f "${file}.png" ] || {
    echo "$file : listed in yourlist, but missing in the directory"
  }
done
#assumes that filenames have no space...
# otherwise use instead:
#  while IFS= read file ; do ...(same inner loop as above)... ; done < yourlist

ve tam tersi:

for file in *.png ; do
  grep "^${file%.png}$" yourlist >/dev/null || {
    echo "$file: present in the directory but not listed in yourlist"
  }
done
#I assume there are no spaces/tabs/? before/after names in 'yourlist'. Change the script accordingly if there are some (or sanitize the list)

1

ls -l | sed 's/\.png$//'

@Roaima tarafından vurgulandığı gibi en doğru yöntemdir. Kaçan olmadan \.pngadlı dosyaları a_png.pngolarak sıralanabilir olacaktır: a_.


kullanarak ls -l, sizin gibi, OP hakkında ne sordu olmadığını, dosya ayrıntılarını verir.
Anthon

1

Basit bir kabuk satırı (ksh, bash veya zsh; çizgi değil):

set -- *.png; printf '%s\n' "${@%.png}"

Basit bir fonksiyon (Eklentiden değil):

ne(){ set -- *.png; printf '%s\n' "${@%.png}"; }

Veya verilen herhangi bir uzantıyı kaldıran bir işlev (varsayılan olarak png):

ne(){ ext=${1:-png}; set -- *."$ext"; printf '%s\n' "${@%.${ext}}"; }

Olarak kullanın:

ne jpg

Çıktı bir yıldız ise *, o uzantıya sahip dosya yoktur.


1

Aşağıdaki beslemeyi deneyebilirsiniz. Üstatınızın çıktısı "." ve tüm dosyalarınızın name.png olacağından ilk sütunu yazdırırsınız:
ls | awk -F"." '{print $1}'


-1

Sed için erişiminiz varsa, bu ne olursa olsun (png, jpg, tiff, vb.) Son dosya uzantısını soracağından daha iyidir.

ls | sed -e 's/\..*$//'

7
Gibi dosya adları için tatili this.is.a.dotty.txt. s/\.[^.]*$//Bunun yerine deneyin .
roaima
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.