' ls -1 ': cum să listezi numele fișierelor fără extensie

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

  • Doriți să aveți grijă cu o cerere ca aceasta. Linux nu are extensii de nume de fișier. Linux are nume de fișiere care pot include sau nu un . î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 numit foo.zip sau my.picture.20160518 sau doar mypic.
  • @hymie I știu, dar elementele mele din acel folder sunt denumite cu .png la final.
  • Ce ‘ este ” extensie „? ‘ nu face parte din denumirea fișierelor Unix; ‘ este reportat de la VMS / NT / Windows orice. Și voi, tineri, coborâți și din peluza mea. 🙂
  • Să ‘ s nu exagereze acest lucru. Sistemul de operare tratează extensiile ca fiind pur și simplu parte a numelui fișierului, dar o mulțime de programe Unix le acordă atenție, de la compilator la GUI. Conceptul nu este cu siguranță străin de unix.
  • De obicei, este sugerat să să evite analiza rezultatului ls și pentru a canaliza ieșirea ls și find, în principal datorită posibilității de a intra în newline,` tab char în numele fișierului. Dacă numele fișierului este The new art of working on .png\NEWLINE files and other formats multe dintre soluțiile propuse vor crea probleme.

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ă la sed 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 rezultatul find sau ls, rezervând adesea surprize bine ascunse … (unele cuvinte și referințe mai multe în răspuns).
  • Înlocuiți probabil find cu ceva de genul echo în ultimul exemplu. Nu este clar ce scop servește acolo find și rezultatele depind de structura directorului (adică dacă aveți un director files.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 pentru ls, deoarece ls presupune că dacă ieșirea standard nu este un terminal (este o conductă, în acest caz).
  • -n opțiunea pentru sed î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șirii ls 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ât sh 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 exemplu find (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 ca Image.png.jpg.png tăind tot timpul cheia (.png). Sub Unix sunt permise numele de fișiere ciudate ca The 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șirea ls 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 numit files.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șirii find, 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ți echo *.png | od -c și ls *.png | od -c. Problema newline nu este o problemă cu ls, 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 analizarea ls 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 ., ca Image.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) în awk, RS. Este sugerat să evitați analiza ieșirii ls 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 interiorul sed -e 's/\.png$//', dar astfel devine un răspuns tocmai scris. 🙁 nota2 puteți încerca să utilizați awk cu ceva de genul ls | 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ți s/\.[^.]*$// în schimb.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *