ls -1
listează elementele mele astfel:
foo.png bar.png foobar.png ...
Vreau să fie listat fără .png
așa:
foo bar foobar ...
(dir conține numai fișiere .png
)
Poate cineva să-mi spună cum să folosesc grep
în acest caz?
Scop: Am un fișier text unde toate numele sunt listate fără extensie. Vreau să creez un script care să compare fișierul text cu dosarul pentru a vedea care fișier lipsește.
Comentarii
Răspuns
Ai nevoie doar de shell pentru acest job.
POSIXly:
for f in *.png; do printf "%s\n" "${f%.png}" done
Cu zsh
:
print -rl -- *.png(:r)
Comentarii
- Acolo ‘ nu este nevoie de
printf
echo ${f%.png}
va fi suficient. - @Conrad: utilizarea echo câștigat ‘ nu funcționează corect în unele cazuri, dacă numele fișierului începeți cu liniuță sau conține secvențe evadate.
- @DavidConrad: consultați și unix.stackexchange.com/a/65819/38906
- @DavidConrad În plus, cred că printf este încorporat, la fel ca echo, cineva mă corectează dacă ‘ greșesc
Răspuns
ls -1 | sed -e "s/\.png$//"
Comanda sed
elimină (adică înlocuiește cu șirul gol) orice șir .png
găsit la sfârșitul din un nume de fișier.
.
este scăpat ca \.
astfel încât să fie interpretat de sed
ca caracter literal .
mai degrabă decât regexp .
(ceea ce înseamnă că se potrivește cu orice ch aracter). $
este ancora de sfârșit de linie, deci nu se potrivește cu .png
în mijlocul unui nume de fișier.
Comentarii
- Cred că OP vrea orice extensie dezbrăcată, dar probabil doar ” ultimul „. Deci poate modificați răspunsul altfel bun cu:
sed 's/\.[^.]*$//'
- da, regexp ar funcționează în acest caz … dar dacă PO dorește acest lucru, ar trebui să spună acest lucru în loc să spună în mod specific că ” doresc să fie listat fără .png ”
-
-1
nu este necesar, fiind implicit aici. - @jlliagre Sunt de acord cu cas că
-1
ar trebui specificat. Este ‘ doar implicit atunci când conducta este pornită, ceea ce este o surpriză ascunsă pentru unii. Deci, explicarea acesteia ajută Fac acest lucru și în scripturile mele, așa că știu ce fel de o utput I ‘ m aștept. - Avertisment În cazul unui nume de fișier cu cheia (
.png
) înainte de o nouă linie, veți șterge chiar și.png
și nu numai ultima. Este mai bine să evitați să analizați și să analizați rezultatul lui ls, rezervând adesea surprize bine ascunse … (unele cuvinte și referințe mai multe în răspuns).
Răspuns
Dacă doriți doar să utilizați bash:
for i in *; do echo "${i%.png}"; done
Ar trebui să ajungeți la grep
atunci când încercați să găsiți potriviri, nu la eliminarea / înlocuirea pentru care sed
mai potrivit:
find . -maxdepth 1 -name "*.png" | sed "s/\.png$//"
Odată ce ați decis că trebuie să creați câteva subdirectoare pentru a aduce ordine în fișierele PNG, puteți schimba cu ușurință acest lucru în:
find . -name "*.png" | sed "s/\.png$//"
Comentarii
- ls -1 | sed ‘ s / .png // ‘ funcționează excelent. Vă mulțumim!
- Soluția
find
canalizată lased
poate prezenta unele probleme dacă găsiți un fișier cu cheia (.png
) ca parte a numelui și chiar înainte de un caracter de linie nouă. Este mai bine să evitați să analizați și să analizați rezultatulfind
sauls
, rezervând adesea surprize bine ascunse … (unele cuvinte și referințe mai multe în răspuns). - Înlocuiți probabil
find
cu ceva de genulecho
în ultimul exemplu. Nu este clar ce scop servește acolofind
și rezultatele depind de structura directorului (adică dacă aveți un directorfiles.png
) - @BroSlow Actualizat la ceva mai sensibil.
Răspuns
Un alt răspuns foarte asemănător (M-am surprins de acest lucru o anumită variantă încă nu a apărut) este:
ls | sed -n "s/\.png$//p"
- Nu aveți nevoie de
-1
opțiunea pentruls
, deoarecels
presupune că dacă ieșirea standard nu este un terminal (este o conductă, în acest caz). -
-n
opțiunea pentrused
înseamnă „nu” tipăriți linia în mod implicit ” - opțiunea
/p
de la sfârșitul substituției înseamnă „… și tipăriți această linie dacă s-a făcut o substituție”.
Netul efectul este acela de a imprima numai acele linii care se termină cu .png
, cu eliminat. Adică, acest lucru se adresează și ușoarei generalizări a întrebării OP, unde directorul nu conține doar fișiere .png
.
este adesea utilă în cazurile în care altfel ați putea folosi grep + sed.
Comentarii
- Îmi place modul în care îngrijirea obișnuia să scrii răspunsul tău. Această soluție va prezenta probleme cu numele fișierelor, inclusiv linii noi , nu va imprima prima parte a numelui. Cu atât mai mult dacă este una mai urâtă cu cheia (
.png
) înainte de noua linie: în acest caz, veți imprima acea parte fără png, fără a șterge doar ultima parte. Este adesea sugerat să evitați analiza (și canalizarea) ieșiriils
deoarece problemele pot fi ascunse chiar acolo unde nu vă gândiți … - @Hastur Sunteți ‘ corectați , în principiu, și celebra pagină despre don ‘ t parse ls enumeră alte probleme (și soluții) la predarea numelor de fișiere patologice. Dar cel mai bun mod de manipulare este evitarea numelor de fișiere patologice (doh!); și dacă poți ‘ t, sau dacă trebuie să fii robust împotriva lor, atunci fie folosești
find
fie – posibil mai bine – folosiți un limbaj mai puternic decâtsh
pentru a le gestiona (faptul căsh
o poate face totul nu ‘ înseamnă că este ‘ cea mai bună alegere în fiecare caz). În primul rând, shell-ul este conceput pentru utilizare. - Sunt de acord, în principiu, cu privire la utilizare, dar această variantă eșuează când aveți un nume de fișier cu fiecare linie nouă înăuntru. Acest lucru poate apărea cu ușurință neobservat, de exemplu, atunci când copiați și lipiți o linie dintr-un pdf într-o interfață grafică, deci credeți că trebuie evitate doar numele de fișier patologice.
- Mai mult decât atât, IMHO Este ‘ ușor să începeți să analizați
ls
, dar este în plin proces de probleme viitoare. Adesea realizăm scripturi pe care îl vom folosi mai târziu, când vom uita deja limita lor … (este ‘ umană, este ‘ obișnuit). Am propus un exemplufind
(cu-exec
și fără țeavă) chiar dacă consider un răspuns mai bun (deoarece coajă pură) cuonglm ‘ s , solid și conform cu posix. - Asta este ceea ce fac ‘ dacă, dintr-un anumit motiv, am vrut să îndepărtez banda
.png
sufix dintr-o listă de nume de fișiere.’ nu l-aș pune într-un script; în schimb, ‘ doar am tastat comanda la promptul shell. Dacă faceți acest lucru, ar fi un memento că ‘ presupun ” sănătos ” nume de fișiere. Sunt o mulțime de lucruri pe care ‘ le voi face într-o comandă manuală unică, când mă simt liber să fac presupuneri despre ceea ce ‘ în directorul curent, că probabil nu aș face ‘ într-un script care ar putea fi refolosit în alt context.
Răspuns
Aș alege basename
(presupunând implementarea GNU):
basename --suffix=.png -- *.png
Comentarii
- Rețineți că, dacă doriți să-l utilizați într-o conductă, vă poate fi util să utilizați numele de bază GNU ‘ s
-z
(sau--zero
) opțiune pentru a produce separare NUL (în loc de separare de linie nouă) ) ieșire.
Răspuns
Puteți utiliza numai comenzi BASH pentru a face acest lucru (fără niciun instrument extern).
for file in *; do echo "${file%.*}"; done
Acest lucru este util atunci când sunteți fără / usr / bin și funcționează bine pentru numele de fișiere l faceți clic pe this.is.image.png și pentru toate extensiile.
Răspuns
nu a fost suficient?
ls -1 | sed "s/\.png//g"
sau, în general, acest
ls -1 | sed "s/\.[a-z]*//g"
va elimina toate extensiile
Comentarii
- A fost, dar și celelalte soluții funcționează.
- Tot sistemul Unix / Unix Like are (sau ar trebui să aibă)
sed
instalat, deoarece este un utilitar obligatoriu după standard. - Într-adevăr, dar
ls
o face oricum fără acea opțiune atunci când ieșirea sa nu este un terminal, ceea ce este cazul aici. - Avertisment
ls -1 | sed 's/\.[a-z]*//g'
va eșua dacă există un nume de fișier caImage.png.jpg.png
tăind tot timpul cheia (.png
). Sub Unix sunt permise numele de fișiere ciudate caThe new art of working on .png?files and other formats.png
unde?
este un caracter newline. Din păcate, toată soluția care va purta / analiza pur și simplu ieșireals
va apărea în proble ms gestionează astfel de cazuri … - De ce calificativul
g
? Doriți să eliminați\.png
numai la sfârșitul liniei, nu de fiecare dată când apare.
Răspuns
Nu este sigur să analizați ls
sau să țineți find
[ 1 , 2 ]
Nu este sigur să analizați (și trimiteți) ieșirea ls
sau find
, în principal pentru că este posibil să găsiți în numele fișierelor caractere neobișnuite ca newline , tab … Aici va funcționa un ciclu de shell pur [ cuonglm ] .
Chiar și comanda find
not piped cu opțiunea -exec
va funcționa:
find ./*.png -exec basename {} .png \;
Actualizări / Note : Puteți utiliza find .
pentru a căuta chiar și fișierele ascunse sau find ./*.png
pentru a obține doar cele care nu sunt ascunse. Cu find *.png -exec ...
puteți avea probleme în cazul în care a fost prezent un fișier numit .png
deoarece find va primi ca opțiune. Puteți adăuga -maxdepth 0
pentru a evita coborârea în directoare numite ca Dir_01.png
sau find ./*.png -prune -exec ...
când maxdepth nu este permisă (mulțumesc Stéphane). Dacă doriți să evitați listarea acelor directoare, ar trebui să adăugați opțiunea -type f
(care ar exclude și alte tipuri de fișiere neregulate). Aruncați o privire către man
pentru o panoramă mai completă despre toate opțiunile disponibile și nu uitați să verificați când sunt compatibile POSIX, pentru o portabilitate mai bună.
Mai multe cuvinte
Se poate întâmpla, de exemplu, ca copierea titlului dintr-un document și lipirea în numele fișierului, una sau mai multe linii noi să se termine în numele fișierului în sine.Putem fi chiar atât de nefericiți încât un titlu poate conține chiar și cheia pe care trebuie să o folosim chiar înainte de o nouă linie:
The new art of working on .png files and other formats.
Dacă doriți să testați, puteți creați astfel de nume de fișiere cu comenzile
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"
Simplul /bin/ls *png
va genera ?
în loc de caracterele care nu se pot printa
A file with two lines?and This is the second.png The new art of working on .png?files and other formats.png
În toate cazurile în care veți trimiteți ieșirea a ls
sau find
următoarea comandă nu va avea niciun indiciu pentru a înțelege dacă linia actuală provine dintr-un nou nume de fișier sau dacă urmează un caracter newline în numele fișierului precedent. Un nume urât într-adevăr, dar încă unul legal.
Un ciclu de shell cu un shell Parameter-Expansion, ${parameter%word}
, în ambele varianta cu printf
sau echo
va funcționa [ cuonglm ], [ Anthon1 ] .
for f in *.png; do printf "%s\n" "${f%.png}" ; done
Din pagina manuală din extensia parametrului Shell [ 3 ]
$ {parametru% cuvânt}
$ {parametru %% cuvânt}… rezultatul extinderii este valoarea parametrului cu cel mai scurt model de potrivire (cazul „%”) sau cel mai lung model de potrivire (cazul „%%”) șters.
Comentarii
- De asemenea, rezultatele
find
este o variabilă de biți (de exemplu, dacă există un director numitfiles.png
) - Dragă @BroSlow, când am scris răspunsul de mai sus I am încercat 13 (toate) celelalte variante prezente în acel moment, prin linie de comandă, într-un script, lansat ca argument al unei invocații shell. Vă rugăm să faceți același lucru și să-mi spuneți dacă se comportă așa cum vă așteptați. Mi-am făcut testele cu
bash 4.3.11
, liniuță 0.5.7-4, zsh (atunci când este necesar) 5.0.2. Simțiți-vă liber să citiți această postare care adaugă ceva mai mult. Sunt de acord cu nota piping ieșiriifind
, pentru aceasta am sugerat în mod expres-exec
, iar eu am scris în titlu.:-)
. - Citiți din nou wiki din nou. Încă cred că trebuie să introduceți exemplul dvs., deoarece ‘ este ceea ce ‘ este discutat aici. Și pentru majoritatea versiunilor moderne ale
ls
nu există nicio problemă când ieșirea este canalizată sau redirecționată, dar așa cum sa menționat în wiki, este posibil să nu funcționeze pentru toți. Majoritatea vor introduce doar?
în locul caracterelor speciale atunci când ieșirea este trimisă la terminal. adică Facețiecho *.png | od -c
șils *.png | od -c
. Problema newline nu este o problemă culs
, ci ‘ este o problemă cu orice comandă care nu ‘ t nul se termină pe ambele părți ale conductei. -
printf "${f%.png}\n"
este greșit. Primul argument este formatul, nu ar trebui să ‘ să utilizați date variabile acolo. Poate fi văzut chiar și ca o vulnerabilitate DoS (încercați cu un fișier%1000000000s.png
de exemplu). - Dvs. ‘ d aveți nevoie de
find ./*.png -prune -exec...
sau ‘ aveți probleme cu numele de fișiere începând cu-
(și fișierele de tip director, rețineți că-maxdepth
nu este portabil)
Răspuns
Utilizați rev
:
ls -1 | rev | cut -f 2- -d "." | rev
rev
inversează toate corzi (linii); tu tai totul după primul „.” și revine inversează rămășița.
Dacă doriți să grep
„alma”:
ls -1 | rev | cut -f 2- -d "." | rev | grep "alma"
Comentarii
-
-1
nu este necesar, fiind implicit aici. - eșuează grav într-un fișier numit
My.2016.Summer.Vacation.png
- @DavidConrad rău meu: / Am corectat la
cut -f 2-
- Acum funcționează cu acel fișier, dar nu încă cu un fișier cu
.png
și o linie nouă imediat după … Se sugerează să evitați analizareals
pentru că îi place să ascundă bine surprizele … 🙂
Răspunde
Dacă aș ști că directorul are doar fișiere cu .png ca extensie, aș fi executat: ls | awk -F. "{print $1}"
Aceasta va returna primul „câmp” pentru orice în cazul în care există un nume de fișier.extension.
Exemplu:
[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
Comentarii
- Din păcate, acesta va eșua pe toate nume de fișiere cu mai mult de un
.
, caImage.1.png
și chiar și pe cele cu nu sunt frumoase nume , cu caractere speciale în interior. ca linie nouă sau cea pe care o veți folosi ca separator de înregistrări (de intrare) înawk
,RS
. Este sugerat să evitați analiza ieșiriils
deoarece îi place să ascundă problema care va apărea atunci când nu vă veți aștepta. Puteți citi mai multe în acele referințe 1 sau 2 . BTW mi-a plăcut ideea de a folosi awk … Am pus câteva exemple într-un singur răspuns. - Este adevărat, însă, având în vedere eșantionul oferit de Colin, ar funcționa foarte bine. Pentru ca acesta să funcționeze pentru cazul pe care l-ați sugerat, ‘ probabil l-am schimbat în: [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 Nu încerc să fiu dificil, dar având în vedere nevoia lui Colin ‘, ‘ nu știu ce ar fi problema analizați ls.
- îmi pare rău … tocmai mi-am dat seama că nu ‘ nu am afișat directorul cu fișierele înainte de a modifica sed ieșirea ‘ 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
- nota1 trebuie să scapi de
.
din\.
în interiorulsed -e 's/\.png$//'
, dar astfel devine un răspuns tocmai scris. 🙁 nota2 puteți încerca să utilizațiawk
cu ceva de genulls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}'
… dar veți avea întotdeauna problema pe care awk nu o poate ști dacă vine linia urmează sau nu o linie nouă în numele fișierului. Am încercat să spun mai bine în răspunsul meu. - Mulțumesc Hastur, am ratat asta :). De asemenea, am renunțat la utilizarea awk în favoarea sed în acest caz.
Răspuns
în funcție de comentariu „Am un fișier text în care sunt listate toate numele fără extensie. Vreau să fac un script PHP care să compare fișierul text cu folderul pentru a vedea ce fișier lipsește”:
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 invers:
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)
Răspuns
ls -l | sed "s/\.png$//"
Este cea mai precisă metodă, evidențiată de @roaima. Fără fișierele \.png
evadate numite a_png.png
ar fi listate ca: a_
.
Comentarii
- folosind
ls -l
, așa cum faceți dvs., oferă detaliile fișierului, nu asta a cerut OP despre.
Răspuns
O linie simplă de shell (ksh, bash sau zsh; nu liniuță):
set -- *.png; printf "%s\n" "${@%.png}"
O funcție simplă (din Fără extensie):
ne(){ set -- *.png; printf "%s\n" "${@%.png}"; }
Sau o funcție care elimină orice extensie dată (png în mod implicit):
ne(){ ext=${1:-png}; set -- *."$ext"; printf "%s\n" "${@%.${ext}}"; }
Folosiți ca:
ne jpg
Dacă ieșirea este un asterisc *
, nu există niciun fișier cu acea extensie.
Răspuns
Puteți încerca următorul feed awk, ieșirea ls superatorului dvs. este „.” și întrucât toate fișierele dvs. vor avea name.png, imprimați prima coloană:
ls | awk -F"." "{print $1}"
Răspuns
Dacă aveți acces la sed, acest lucru este mai bun, deoarece va elimina ultima extensie de fișier, indiferent de ce este (png, jpg, tiff, etc …)
ls | sed -e "s/\..*$//"
Comentarii
- Pauze pentru nume de fișiere precum
this.is.a.dotty.txt
. Încercațis/\.[^.]*$//
în schimb.
.
în ele. Deși convenția spune să vă denumiți fișierele cu.png
la sfârșit, nu există niciun motiv pentru care nu pot ‘ să am un fișier png numitfoo.zip
saumy.picture.20160518
sau doarmypic
.ls
și pentru a canaliza ieșireals
șifind
, în principal datorită posibilității de a intra înnewline
,` tab char în numele fișierului. Dacă numele fișierului esteThe new art of working on .png\NEWLINE files and other formats
multe dintre soluțiile propuse vor crea probleme.