' ls -1 ': jak wyświetlić nazwy plików bez rozszerzenia

ls -1 wyświetla moje elementy w następujący sposób:

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

Chcę, aby była wyświetlana bez elementu .png na przykład:

foo bar foobar ... 

(katalog zawiera tylko .png pliki)

Czy ktoś może mi powiedzieć, jak używać grep w tym przypadku?

Cel: Mam plik tekstowy, w którym wszystkie nazwy są wymienione bez rozbudowa. Chcę utworzyć skrypt porównujący plik tekstowy z folderem, aby sprawdzić, którego pliku brakuje.

Komentarze

  • Chcesz być ostrożny z taka prośba. Linux nie ma rozszerzeń nazw plików. Linux ma nazwy plików, które mogą, ale nie muszą, zawierać .. Chociaż konwencja nakazuje nazywanie plików za pomocą .png na końcu, nie ma powodu, dla którego mogę ' t mieć plik png o nazwie foo.zip lub my.picture.20160518 lub po prostu mypic.
  • @hymie I Wiem, ale wszystkie moje elementy w tym folderze mają na końcu nazwę .png.
  • Co ' s an ” rozszerzenie „? To ' nie jest częścią uniksowego nazewnictwa plików; to ' jest przeniesione z VMS / NT / Windows cokolwiek. Wy, młodzi, też zejdźcie z mojego trawnika. 🙂
  • Niech ' nie przesadza. System operacyjny traktuje rozszerzenia jako po prostu będące częścią nazwy pliku, ale wiele programów uniksowych zwraca na nie uwagę, od kompilatora po GUI. Koncepcja z pewnością nie jest obca unixowi.
  • Zwykle zaleca się unikanie analizowania danych wyjściowych ls i potokować wyjście ls i find, głównie z powodu możliwości poniesienia w newline,` tabulator w nazwie pliku. Jeśli nazwa pliku to The new art of working on .png\NEWLINE files and other formats, wiele z proponowanych rozwiązań spowoduje problemy.

Odpowiedź

Do tego zadania potrzebujesz tylko powłoki.

POSIXly:

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

Z zsh:

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

Komentarze

  • Tam ' nie ma potrzeby printf; echo ${f%.png} wystarczy.
  • @Conrad: użycie echo won ' nie działa poprawnie w niektórych przypadkach, jeśli nazwa pliku zaczynaj od myślnika lub zawiera sekwencje ze zmiennymi znakami.
  • @DavidConrad: Zobacz także unix.stackexchange.com/a/65819/38906
  • @DavidConrad Dodatkowo uważam, że printf jest wbudowany, tak jak echo, ktoś mnie poprawia, jeśli ' m źle

Odpowiedź

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

Polecenie sed usuwa (czyli zamienia na pusty ciąg) dowolny ciąg .png znaleziony na końcu z nazwa pliku.

. jest zmieniany jako \., więc jest interpretowany przez sed jako literał . znak zamiast wyrażenia regularnego . (co oznacza, że pasuje do dowolnego ch aracter). $ jest kotwicą końca linii, więc nie pasuje do .png w środku nazwy pliku.

Komentarze

  • Myślę, że OP chce usunąć dowolne rozszerzenie, ale prawdopodobnie tylko ” last one „. Więc może zmodyfikuj swoją skądinąd dobrą odpowiedź: sed 's/\.[^.]*$//'
  • tak, to wyrażenie regularne zadziała w takim przypadku … ale jeśli operator tego chce, powinien to powiedzieć zamiast mówić konkretnie, że ” chce, aby był wymieniony bez pliku .png ”
  • -1 nie jest konieczne, ponieważ jest tutaj domyślne.
  • @jlliagre Zgadzam się z przypadkiem, że -1. ' jest domyślny tylko wtedy, gdy włączony jest potok, co jest dla niektórych ukrytą niespodzianką. Dlatego wyraźne wskazanie go pomaga rozumiem. Robię to również w moich skryptach, więc wiem, jakiego rodzaju o utput I ' oczekuję.
  • Ostrzeżenie W przypadku nazwy pliku z kluczem (.png) przed znakiem nowej linii usuniesz nawet ten .png i nie tylko ostatni. Lepiej unikać potokowania i parsowania wyjścia ls, zawiera on często dobrze ukryte niespodzianki … (więcej słów i odniesień w odpowiedzi).

Odpowiedź

Jeśli chcesz tylko użyć bash:

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

Podczas próby znalezienia dopasowań należy sięgnąć po grep, a nie za usuwanie / zastępowanie tego sed jest bardziej odpowiednie:

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

Gdy zdecydujesz, że musisz utworzyć podkatalogi, aby uporządkować pliki PNG, możesz to łatwo zmienić na:

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

Komentarze

  • ls -1 | sed ' s / .png // ' działa świetnie. Dziękuję!
  • Rozwiązanie find piped do sed może powodować pewne problemy, jeśli znajdziesz plik z kluczem (.png) jako częścią nazwy i tuż przed znakiem nowego wiersza. Lepiej unikać potokowania i przeanalizowania wyniku find lub ls, zawiera on często dobrze ukryte niespodzianki … (niektóre słowa i więcej odniesień w odpowiedzi).
  • Prawdopodobnie zamień find na coś w rodzaju echo w ostatnim przykładzie. Nie jest jasne, do jakiego celu służy find, a wyniki zależą od struktury katalogów (tj. Jeśli masz katalog files.png)
  • @BroSlow Zaktualizowano do czegoś bardziej sensownego.

Odpowiedź

Kolejna bardzo podobna odpowiedź (jestem zaskoczony konkretny wariant jeszcze się nie pojawił) to:

ls | sed -n "s/\.png$//p" 
  • Nie potrzebujesz -1 opcja ls, ponieważ ls zakłada, że jeśli standardowym wyjściem nie jest „ta terminal” (w tym przypadku jest to potok).
  • opcja -n sed oznacza „domyślnie nie drukuj linii”
  • opcja /p na końcu podstawienia oznacza „… i wydrukuj tę linię, jeśli dokonano podstawienia”.

Sieć Efektem tego jest wydrukowanie tylko tych wierszy, które kończą się na .png, z usunięto. Oznacza to, że służy to również niewielkiemu uogólnieniu pytania OP, gdzie katalog nie zawiera tylko plików .png.

jest często przydatna w przypadkach, gdy w innym przypadku można by użyć grep + sed.

Komentarze

  • Podoba mi się wcześniej pisałeś swoją odpowiedź. To rozwiązanie spowoduje problemy z nazwami plików zawierającymi nowe linie , nie wypisze pierwszej części nazwy. Jeszcze bardziej, jeśli jest to bardziej nieprzyjemna z kluczem (.png) przed znakiem nowej linii: w takim przypadku wydrukujesz tę część bez png, nie usuwając tylko ostatniej części. Często zaleca się unikanie analizowania (i potokowania) wyniku ls ponieważ problemy mogą być ukryte tam, gdzie nie myślisz …
  • @Hastur You ' ponownie popraw w zasadzie, a słynna strona o don ' t parse ls zawiera listę dalszych problemów (i rozwiązań) podczas obsługi patologicznych nazw plików. Ale najlepszym sposobem na to jest unikanie patologicznych nazw plików (doh!); a jeśli możesz ' t, lub jeśli musisz być odporny na nie, użyj find lub – prawdopodobnie lepiej – do zarządzania nimi użyj bardziej zaawansowanego języka niż sh (fakt, że sh może wszystko to nie ' oznacza, że ' jest najlepszym wyborem w każdym przypadku). Powłoka została zaprojektowana najpierw pod kątem użyteczności.
  • Zasadniczo zgadzam się co do użyteczności, ale ten wariant zawodzi, gdy masz nazwę pliku z każdym nowym wierszem w środku. Może się to łatwo zdarzyć niezauważone, na przykład podczas kopiowania i wklejania linii z pliku PDF do GUI, więc myślisz, że należy unikać patologicznych nazw plików .
  • Ponadto IMHO Łatwo jest ' rozpocząć analizę ls, ale wiąże się to z przyszłymi problemami. Często tworzymy skrypty których użyjemy później, kiedy już zapomnimy o ich ograniczeniach … (to ' człowiek, to ' zwykle). zaproponowałem find przykład (z -exec i bez kreski) nawet jeśli uznam to za lepszą (ponieważ czysta powłoka), odpowiedz na cuonglm ' s , solidny i zgodny z POSIX.
  • To jest prawie to, co ' d zrobię, jeśli z jakiegoś powodu chcę usunąć pasek .png przyrostek z listy nazw plików.Nie ' nie umieszczałbym tego w skrypcie; zamiast tego ' d po prostu wpisuję polecenie w wierszu poleceń powłoki. Byłoby to przypomnieniem, że ' m zakładam ” rozsądny ” nazwy plików. Jest wiele rzeczy, które ' zrobię za pomocą jednorazowego ręcznego polecenia, kiedy mogę swobodnie przyjąć założenia dotyczące ' s w bieżącym katalogu, którego prawdopodobnie nie zrobiłbym ' w skrypcie, który mógłby zostać ponownie użyty w innym kontekście.

Odpowiedź

I „bym wybrał basename (zakładając implementację GNU):

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

Komentarze

  • Zauważ, że jeśli chcesz użyć go w potoku, pomocne może być użycie GNU basename ' s -z (lub --zero), aby utworzyć znak rozdzielony znakiem NUL (zamiast znaku nowego wiersza ).

Odpowiedź

Możesz do tego użyć tylko poleceń BASH (bez żadnych zewnętrznych narzędzi).

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

Jest to przydatne, gdy „nie masz / usr / bin i działa dobrze dla nazw plików l ike this.is.image.png i dla wszystkich rozszerzeń.

Odpowiedź

Czy to nie wystarczyło?

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

lub ogólnie rzecz biorąc, to

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

spowoduje usunięcie wszystkich rozszerzeń

Komentarze

  • Tak, ale inne rozwiązania też działają.
  • Wszystkie systemy Unix / Unix Like mają (lub powinny mieć) sed, ponieważ jest to narzędzie obowiązkowe według standardu.
  • Rzeczywiście, ale ls i tak robi to bez tej opcji, gdy jego wyjście nie jest terminalem, co ma miejsce w tym przypadku.
  • Ostrzeżenie ls -1 | sed 's/\.[a-z]*//g' zakończy się niepowodzeniem, jeśli istnieje nazwa pliku Image.png.jpg.png ciągłe wycinanie klucza (.png). W systemie Unix dozwolone są dziwne nazwy plików jako The new art of working on .png?files and other formats.png, gdzie ? to znak nowej linii. Niestety, każde rozwiązanie, które po prostu potokuje / przeanalizuje wyjście ls, spowoduje problem ms zarządza takimi przypadkami …
  • Dlaczego kwalifikator g? Chcesz usunąć \.png tylko na końcu linii, a nie za każdym razem, gdy się pojawia.

Odpowiedź

Nie jest bezpiecznie analizować ls ani potokować find [ 1 , 2 ]

Nie jest bezpiecznie przeanalizować (i potokować) dane wyjściowe ls lub find, głównie dlatego, że można je znaleźć w nazwach plików nietypowe znaki jak nowa linia , tabulator … Tutaj będzie działał czysty cykl powłoki [ cuonglm ] .
Nawet polecenie find nie potokowane z opcją -exec będzie działać:

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

Aktualizacje / Notatki : możesz użyć find . do wyszukiwania nawet ukrytych plików lub find ./*.png dostać tylko te, które nie są ukryte. Z find *.png -exec ... możesz mieć problem w przypadku, gdy obecny był plik o nazwie .png, ponieważ find otrzyma go jako opcję. Możesz dodać -maxdepth 0, aby uniknąć zejścia do katalogów o nazwach Dir_01.png lub find ./*.png -prune -exec ..., gdy maxdepth jest niedozwolone (dzięki Stéphane). Jeśli chcesz uniknąć wyświetlania tych katalogów, powinieneś dodać opcję -type f (która wykluczyłaby również inne typy nieregularnych plików). Zajrzyj do man, aby uzyskać pełniejszą panoramę wszystkich dostępnych opcji i pamiętaj, aby sprawdzić, czy są one zgodne z POSIX, aby zapewnić lepszą przenośność.

Jeszcze kilka słów

Może się na przykład zdarzyć, że kopiując tytuł z dokumentu i wklejając do nazwy pliku, jedna lub więcej nowej linii zakończy się w samej nazwie pliku.Możemy mieć nawet tyle pecha, że tytuł może zawierać nawet klucz, którego musimy użyć tuż przed nową linią:

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

Jeśli chcesz przetestować, możesz utwórz takie nazwy plików za pomocą poleceń

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" 

Prosty /bin/ls *png wyświetli ? zamiast znaków niedrukowalnych

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

We wszystkich przypadkach, w których potokuj wyjście z ls lub find poniższe polecenie nie będzie miało żadnej wskazówki do zrozumienia czy obecna linia pochodzi z nowej nazwy pliku lub jeśli następuje po znaku nowej linii w poprzedniej nazwie pliku . Paskudna nazwa rzeczywiście, ale wciąż legalna.

Cykl powłoki z rozszerzeniem parametrów powłoki, ${parameter%word}, w obu wariant z printf lub echo będzie działać [ cuonglm ], [ Anthon1 ] .

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

Ze strony podręcznika rozszerzenia parametrów powłoki [ 3 ]

$ {parametr% słowo}
$ {parametr %% słowo}

… wynikiem interpretacji jest wartość parametru z najkrótszym pasującym wzorcem (przypadek „%”) lub Usunięto najdłuższy pasujący wzorzec (przypadek „%%”).

Komentarze

  • Również wyniki find to zmienna bitowa (na przykład jeśli istnieje katalog o nazwie files.png)
  • Drogi @BroSlow, kiedy napisałem odpowiedź powyżej ja wypróbowałem 13 (wszystkich) innych wariantów obecnych w tym momencie, z wiersza poleceń, w skrypcie, uruchomionym jako argument wywołania powłoki. Zrób to samo i powiedz mi, czy zachowują się w oczekiwany sposób. Przeprowadziłem testy z bash 4.3.11, myślnikiem 0.5.7-4, zsh (w razie potrzeby) 5.0.2. Zapraszam do przeczytania tego posta , który zawiera coś więcej. Zgadzam się z uwagą dotyczącą pipingu wyjścia find, w tym przypadku wyraźnie zasugerowałem -exec i napisałem w tytule. :-).
  • Ponownie przeczytaj wiki. Nadal uważam, że w swoim przykładzie trzeba potokować potokiem, ponieważ omawiamy tutaj ' to, co '. W przypadku większości nowoczesnych wersji ls nie ma żadnego problemu, gdy dane wyjściowe są przesyłane potokiem lub przekierowywane, ale jak wspomniano na wiki, może nie działać dla wszystkich. Większość wstawia ? zamiast znaków specjalnych tylko wtedy, gdy dane wyjściowe są wysyłane do terminala. tj. wykonaj echo *.png | od -c i ls *.png | od -c. Problem z nową linią nie dotyczy ls, ale ' jest problemem z każdym poleceniem, które nie ' t zerowe zakończenie po obu stronach potoku.
  • printf "${f%.png}\n" jest błędne. Pierwszym argumentem jest format, w którym nie należy ' używać zmiennych danych. Może to być nawet postrzegane jako luka DoS (spróbuj na przykład z plikiem %1000000000s.png).
  • Ty ' d potrzebujesz find ./*.png -prune -exec... lub ' d masz problemy z nazwami plików zaczynającymi się od - (i plikami o type, pamiętaj, że -maxdepth nie jest przenośny)

Odpowiedź

Użyj rev:

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

rev odwraca wszystkie struny (linie); wycinasz wszystko po pierwszym „.” i rev odwraca pozostałość.

Jeśli chcesz grep „alma”:

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

Komentarze

  • Element -1 nie jest konieczny, ponieważ jest tutaj domyślny.
  • To źle działa na pliku o nazwie My.2016.Summer.Vacation.png
  • @DavidConrad mój błąd: / Poprawiłem na cut -f 2-
  • Teraz działa z tym plikiem, ale jeszcze nie działa z plikiem z .png i nową linią tuż po … Zaleca się unikanie analizowania ls ponieważ uwielbia dobrze ukrywać niespodzianki … 🙂

Odpowiedz

Gdybym wiedział, że katalog zawiera tylko pliki z rozszerzeniem .png, po prostu wykonałbym: ls | awk -F. "{print $1}"

To zwróci pierwsze „pole” dla wszystko, gdzie jest nazwa pliku.rozszerzenie.

Przykład:

[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 

Komentarze

  • Niestety wszystko się nie powiedzie nazwy plików z więcej niż jednym ., jako Image.1.png, a nawet te z nieładnym nazwy , ze znakami specjalnymi w środku. jako nowy wiersz lub ten, którego będziesz używać jako (wejściowego) separatora rekordów w awk, RS. Zaleca się unikanie analizowania wyników ls, ponieważ uwielbia ukrywać problem, który pojawi się, gdy się nie spodziewasz. Więcej informacji można znaleźć w odnośnikach 1 lub 2 . Przy okazji fajny pomysł na użycie awk … Podałem kilka przykładów w jednej odpowiedzi.
  • To prawda, jednak biorąc pod uwagę próbkę dostarczoną przez Colina, działałoby to dobrze. Aby to działało w przypadku, który zasugerowałeś, ' d prawdopodobnie zmieniam go na: [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 Nie staram się być trudne, ale biorąc pod uwagę potrzebę Colina ', ' nie jestem pewien, jaki byłby problem analizować ls.
  • przepraszam … Właśnie sobie uświadomiłem, że nie ' nie pokazałem katalogu z plikami sprzed seda, modyfikując wyjście ' ls ' [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
  • note1 , musisz zmienić znaczenie . w \. wewnątrz sed -e 's/\.png$//', ale staje się to właśnie napisaną odpowiedzią. 🙁 note2 możesz spróbować użyć awk z czymś takim jak ls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}' … ale będziesz mieć zawsze problem, którego awk nie może wiedzieć, czy nadchodzi linia, jest następujący po znaku nowej linii w nazwie pliku. Próbowałem powiedzieć lepiej w mojej odpowiedzi.
  • Dzięki Hastur, przegapiłem to :). W tym przypadku porzuciłem też awk na rzecz seda.

Odpowiedz

zgodnie z komentarz „Mam plik tekstowy, w którym wymienione są wszystkie nazwy bez rozszerzenia. Chcę utworzyć skrypt PHP porównujący plik tekstowy z folderem, aby zobaczyć, którego pliku brakuje”:

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 

i odwrotnie:

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) 

Odpowiedź

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

Jest to najdokładniejsza metoda, jak podkreśla @roaima. Bez zmian znaczenia \.png pliki o nazwie a_png.png byłyby wymienione jako: a_.

Komentarze

  • używając ls -l, tak jak ty, podajesz szczegóły pliku, a nie o to poprosił OP około.

Odpowiedź

Prosta linia powłoki (ksh, bash lub zsh; nie myślnik):

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

Prosta funkcja (bez rozszerzenia):

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

Lub funkcja, która usuwa dowolne podane rozszerzenie (domyślnie png):

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

Użyj jako:

ne jpg 

Jeśli wynikiem jest gwiazdka *, nie istnieje plik z tym rozszerzeniem.

Odpowiedź

Możesz wypróbować następujący kanał, awk, wyjście ls, twoim superatorem jest „.” a ponieważ wszystkie twoje pliki będą miały nazwę.png, wydrukujesz pierwszą kolumnę:
ls | awk -F"." "{print $1}"

Odpowiedź

Jeśli masz dostęp do seda, jest to lepsze, ponieważ usunie ostatnie rozszerzenie pliku, bez względu na to, jakie to jest (png, jpg, tiff itp.)

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

Komentarze

  • Przerwy w nazwach plików, takich jak this.is.a.dotty.txt. Spróbuj zamiast tego s/\.[^.]*$//.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *