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
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 dosed
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 wynikufind
lubls
, zawiera on często dobrze ukryte niespodzianki … (niektóre słowa i więcej odniesień w odpowiedzi). - Prawdopodobnie zamień
find
na coś w rodzajuecho
w ostatnim przykładzie. Nie jest jasne, do jakiego celu służyfind
, a wyniki zależą od struktury katalogów (tj. Jeśli masz katalogfiles.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
opcjals
, 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) wynikuls
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, żesh
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łemfind
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 plikuImage.png.jpg.png
ciągłe wycinanie klucza (.png
). W systemie Unix dozwolone są dziwne nazwy plików jakoThe 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ściels
, 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 nazwiefiles.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ściafind
, 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. wykonajecho *.png | od -c
ils *.png | od -c
. Problem z nową linią nie dotyczyls
, 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 analizowanials
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
.
, jakoImage.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 wawk
,RS
. Zaleca się unikanie analizowania wynikówls
, 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ątrzsed -e 's/\.png$//'
, ale staje się to właśnie napisaną odpowiedzią. 🙁 note2 możesz spróbować użyćawk
z czymś takim jakls | 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 tegos/\.[^.]*$//
.
.
. Chociaż konwencja nakazuje nazywanie plików za pomocą.png
na końcu, nie ma powodu, dla którego mogę ' t mieć plik png o nazwiefoo.zip
lubmy.picture.20160518
lub po prostumypic
.ls
i potokować wyjściels
ifind
, głównie z powodu możliwości poniesienia wnewline
,` tabulator w nazwie pliku. Jeśli nazwa pliku toThe new art of working on .png\NEWLINE files and other formats
, wiele z proponowanych rozwiązań spowoduje problemy.