' ls -1 ': come elencare i nomi di file senza estensione

ls -1 elenca i miei elementi in questo modo:

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

Voglio che sia elencato senza .png in questo modo:

foo bar foobar ... 

(la directory contiene solo .png file)

Qualcuno può dirmi come usare grep in questo caso?

Scopo: ho un file di testo in cui tutti i nomi sono elencati senza il estensione. Voglio creare uno script che confronti il file di testo con la cartella per vedere quale file manca.

Commenti

  • Vuoi fare attenzione con una richiesta come questa. Linux non ha estensioni dei nomi di file. Linux ha nomi di file che possono includere o meno un . al loro interno. Sebbene la convenzione stabilisca di denominare i file con .png alla fine, non cè motivo per cui ‘ non abbia un file png denominato foo.zip o my.picture.20160518 o semplicemente mypic.
  • @hymie I sai, ma i miei elementi in quella cartella sono tutti denominati con .png alla fine.
  • Cosa ‘ è un ” estensione “? Questo ‘ non fa parte della denominazione dei file Unix; ‘ viene trasferito da VMS / NT / Windows qualunque. E anche voi ragazzi scendete dal mio prato. 🙂
  • Non ‘ esagerare. Il sistema operativo considera le estensioni semplicemente come parte del nome del file, ma molti programmi unix prestano loro attenzione, dal compilatore alla GUI. Il concetto non è certamente estraneo a Unix.
  • Di solito si consiglia di evitare di analizzare loutput di ls e per reindirizzare loutput di ls e find, principalmente perché la possibilità di incorrere in newline,` tab char nel nome del file. Se il nome del file è The new art of working on .png\NEWLINE files and other formats molte delle soluzioni proposte creeranno problemi.

Risposta

Hai solo bisogno della shell per questo lavoro.

POSIZIONARE:

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

Con zsh:

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

Commenti

  • Là ‘ non è necessario printf; echo ${f%.png} sarà sufficiente.
  • @Conrad: luso di echo non ha ‘ funzionato correttamente in alcuni casi, se il nome del file iniziare con un trattino o contenere sequenze di escape.
  • @DavidConrad: vedere anche unix.stackexchange.com/a/65819/38906
  • @DavidConrad Inoltre, credo che printf sia integrato, proprio come echo, qualcuno mi corregge se ‘ sbaglio

Risposta

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

Il comando sed rimuove (ovvero, sostituisce con la stringa vuota) qualsiasi stringa .png trovata alla end di un nome file.

Il . è sottoposto a escape come \. in modo che venga interpretato da sed come carattere letterale . anziché come espressione regolare . (che significa che corrisponde a qualsiasi ch carattere). $ è lancora di fine riga, quindi “non corrisponde a .png nel mezzo del nome di un file.

Commenti

  • Penso che lOP voglia rimuovere qualsiasi estensione, ma probabilmente solo ” last one “. Quindi forse modifica la tua risposta altrimenti valida con: sed 's/\.[^.]*$//'
  • sì, quella regexp lo farebbe funziona in quel caso … ma se lOP lo vuole, dovrebbe dirlo invece di dire specificamente che ” lo vuole elencato senza il .png ”
  • -1 non è necessario, essendo limpostazione predefinita qui.
  • @jlliagre Sono daccordo con cas che -1 dovrebbe essere specificato. ‘ è solo limpostazione predefinita quando pipe è acceso, il che è una sorpresa nascosta per alcuni. Quindi renderlo esplicito aiuta Lo faccio anche nei miei script, quindi so che tipo di o utput Mi ‘ mi aspetto.
  • Avviso Nel caso di un nome file con la chiave (.png) prima di un carattere di nuova riga cancellerai anche quel .png e non solo lultimo. È meglio evitare di pipe e analizzare loutput di ls, che riserva spesso sorprese ben nascoste … (alcune parole e riferimenti in più nella risposta).

Risposta

Se vuoi solo usare bash:

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

Dovresti cercare grep quando cerchi di trovare corrispondenze, non per rimuovere / sostituire quello che sed è più appropriato:

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

Una volta deciso che è necessario creare alcune sottodirectory per mettere ordine nei file PNG, puoi facilmente cambiarlo in:

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

Commenti

  • ls -1 | sed ‘ s / .png // ‘ funziona alla grande. Grazie!
  • La soluzione find piped a sed può presentare alcuni problemi se trovi un file con la chiave (.png) come parte del nome e appena prima di un carattere di nuova riga. È meglio evitare di pipe e analizzare loutput di find o ls, riserva spesso sorprese ben nascoste … (alcune parole e riferimenti più nella risposta).
  • Probabilmente sostituire find con qualcosa come echo nellultimo esempio. Non è chiaro quale sia lo scopo di find e i risultati dipendono dalla struttura della directory (ad esempio, se hai una directory files.png)
  • @BroSlow Aggiornato a qualcosa di più sensato.

Rispondi

Unaltra risposta molto simile (sono “sorpreso di questo una variante particolare non è ancora apparsa) è:

ls | sed -n "s/\.png$//p" 
  • Non è necessario -1 opzione a ls, poiché ls presuppone che se loutput standard non è “un terminale (in questo caso” una pipe).
  • lopzione -n per sed significa “non stampare la riga per impostazione predefinita”
  • lopzione /p alla fine della sostituzione significa “… e stampa questa riga se è stata effettuata una sostituzione”.

La rete leffetto di ciò è stampare solo quelle righe che terminano con .png, con rimosso. Cioè, questo soddisfa anche la leggera generalizzazione della domanda dellOP, dove la directory non “contiene solo .png file.

Il sed -n è spesso utile nei casi in cui potresti altrimenti usare grep + sed.

Commenti

  • Mi piace come la cura hai usato per scrivere la tua risposta. Questa soluzione presenterà problemi con i nomi dei file inclusi newline , non stamperà la prima parte del nome. Ancor di più seèpiù cattiva con la chiave (.png) prima del carattere di nuova riga: in tal caso stamperai quella parte senza png, non cancellando solo lultima parte. È spesso suggerito per evitare di analizzare (e reindirizzare) loutput di ls perché i problemi possono essere nascosti proprio dove non stai pensando …
  • @Hastur Tu ‘ hai corretto , in linea di principio, e la famosa pagina su don ‘ t parse ls elenca ulteriori problemi (e soluzioni) quando si consegnano nomi di file patologici. Ma il modo migliore per gestirlo è evitare di avere nomi di file patologici (doh!); e se puoi ‘ t, o se devi essere robusto contro di loro, allora usa find o – forse meglio – usa un linguaggio più potente di sh per gestirli (il fatto che sh può fare tutto non ‘ t significa che ‘ è la scelta migliore in ogni caso). La shell è progettata innanzitutto per lusabilità.
  • Sono daccordo, in linea di principio, sullusabilità, ma questa variante fallisce quando hai un nome file con ogni nuova riga allinterno. Questo può facilmente accadere inosservato, ad esempio, quando copi e incolli una riga da un pdf in una GUI, quindi pensi solo che siano evitati nomi di file patologici.
  • Inoltre IMHO È ‘ facile iniziare ad analizzare ls, ma è alle porte di problemi futuri. Spesso creiamo script che useremo in seguito, quando già dimenticheremo il loro limite … (è ‘ umano, ‘ è normale). Ho proposto un find esempio (con -exec e senza pipe) anche se ritengo una migliore (perché pura shell) risponda alla cuonglm ‘ s una , solida e conforme a posix.
  • Questo è più o meno quello che ‘ farei se, per qualche motivo, volessi rimuovere il .png suffisso da un elenco di nomi di file.Non ‘ lo metterei in uno script; invece ‘ digito semplicemente il comando al prompt della shell. In questo modo mi ricorderei che ‘ m assumendo ” sano di mente ” nomi di file. Ci sono molte cose che ‘ farò in un comando manuale una tantum, quando mi sento libero di fare supposizioni su cosa ‘ nella directory corrente, cosa che probabilmente non ‘ farei in uno script che potrebbe essere riutilizzato in un altro contesto.

Risposta

Preferisco basename (assumendo limplementazione GNU):

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

Commenti

  • Nota che se vuoi usarlo in una pipe, potresti trovare utile usare GNU basename ‘ s -z (o --zero) per produrre valori separati da NUL (anziché separati da nuova riga ).

Risposta

Puoi usare solo comandi BASH per farlo (senza strumenti esterni).

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

Questo è utile quando sei senza / usr / bin e funziona bene per i nomi di file l come this.is.image.png e per tutte le estensioni.

Risposta

“non era abbastanza?

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

o in generale, questo

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

rimuoverà tutte le estensioni

Commenti

  • Lo era, ma funzionano anche le altre soluzioni.
  • Tutti i sistemi Unix / Unix Like hanno (o dovrebbero avere) sed installato poiché è unutilità obbligatoria secondo lo standard.
  • Effettivamente, ma ls lo fa comunque senza questa opzione quando il suo output non è un terminale, come è il caso qui.
  • Avviso ls -1 | sed 's/\.[a-z]*//g' non funzionerà se è presente un nome file come Image.png.jpg.png tagliando continuamente la chiave (.png). In Unix sono consentiti strani nomi di file come The new art of working on .png?files and other formats.png dove ? è un carattere di nuova riga. Sfortunatamente tutta la soluzione che semplicemente reindirizzerà / analizzerà loutput di ls incorrerà in problemi ms gestire tali casi …
  • Perché il qualificatore g? Vuoi rimuovere \.png solo alla fine della riga, non ogni volta che appare.

Risposta

Non è sicuro analizzare ls o reindirizzare find [ 1 , 2 ]

Non è sicuro analizzare (e reindirizzare) loutput di ls o find, principalmente perché è possibile trovare nei nomi di file caratteri non usuali come la nuova riga , la scheda … Qui un ciclo di shell puro funzionerà [ cuonglm ] .
Anche il comando find non convogliato con lopzione -exec funzionerà:

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

Aggiornamenti / Note : puoi utilizzare find . per cercare anche i file nascosti oppure find ./*.png per ottenere solo quelli non nascosti. Con find *.png -exec ... puoi avere problemi nel caso fosse presente un file chiamato .png perché find lo otterrà come opzione. Puoi aggiungere -maxdepth 0 per evitare di scendere in directory denominate Dir_01.png o find ./*.png -prune -exec ... quando maxdepth non è consentito (grazie Stéphane). Se vuoi evitare di elencare quelle directory dovresti aggiungere lopzione -type f (che escluderebbe anche altri tipi di file non regolari). Dai unocchiata al man per un panorama più completo su tutte le opzioni disponibili e ricordati di controllare quando sono conformi a POSIX, per una migliore portabilità.

Qualche parola in più

Può accadere, ad esempio, che copiando il titolo da un documento e incollandolo nel nome del file, uno o più newline finiscano nel nome del file stesso.Possiamo anche essere così sfortunati che un titolo possa contenere anche la chiave che dobbiamo usare appena prima di una nuova riga:

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

Se vuoi provare, puoi creare nomi di file come questo con i comandi

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" 

Il semplice /bin/ls *png restituirà ? invece dei caratteri non stampabili

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

In tutti i casi in cui indirizza loutput di ls o find il seguente comando non avrà alcun suggerimento da capire se la riga attuale proviene da un nuovo nome file o se segue un carattere nuova riga nel precedente nome file . Un nome brutto in effetti, ma ancora legale.

Un ciclo di shell con unespansione dei parametri della shell, ${parameter%word}, in entrambi la variante con printf o echo funzionerà [ cuonglm ], [ Anthon1 ] .

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

Dalla pagina man dellespansione dei parametri della shell [ 3 ]

$ {parametro% parola}
$ {parametro %% parola}

… il risultato dellespansione è il valore del parametro con il modello di corrispondenza più breve (il caso %) o il modello di corrispondenza più lungo (il caso %%) eliminato.

Commenti

  • Anche i risultati del tuo find sono un po variabili (ad esempio se cè una directory chiamata files.png)
  • Gentile @BroSlow, quando ho scritto la risposta sopra io provato 13 (tutte) delle altre varianti presenti in quel momento, da riga di comando, in uno script, lanciato come argomento di una invocazione di shell. Per favore, fai lo stesso e dimmi se si comportano come ti aspetti. Ho eseguito i miei test con bash 4.3.11, trattino 0.5.7-4, zsh (quando necessario) 5.0.2. Sentiti libero di leggere questo post che aggiunge qualcosa in più. Sono daccordo sulla nota di piping loutput di find, per questo ho espressamente suggerito -exec e ho scritto nel titolo. :-).
  • Rileggi di nuovo il wiki. Penso ancora che tu debba reindirizzare nel tuo esempio, dal momento che ‘ è ciò che ‘ viene discusso qui. E per la maggior parte delle versioni moderne di ls non cè alcun problema quando loutput viene reindirizzato o reindirizzato, ma come menzionato in wiki potrebbe non funzionare per tutti. La maggior parte inserirà solo ? al posto di caratteri speciali quando loutput viene inviato al terminale. ad es. echo *.png | od -c e ls *.png | od -c. Il problema di nuova riga non è un problema con ls, è ‘ è un problema con qualsiasi comando che non ‘ t terminare null su entrambi i lati del pipe.
  • printf "${f%.png}\n" è sbagliato. Il primo argomento è il formato, non dovresti ‘ utilizzare dati variabili al suo interno. Può anche essere vista come una vulnerabilità DoS (prova con un %1000000000s.png file per esempio).
  • Tu ‘ d è necessario find ./*.png -prune -exec... o ‘ hai problemi con nomi di file che iniziano con - (e file di type directory, nota che -maxdepth non è portabile)

Rispondi

Utilizza rev:

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

rev inverte tutte le stringhe (linee); hai tagliato tutto dopo il primo “.” e rev ripristina il resto.

Se desideri grep “alma”:

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

Commenti

  • -1 non è necessario, essendo limpostazione predefinita qui.
  • Questo non funziona correttamente su un file denominato My.2016.Summer.Vacation.png
  • @DavidConrad mio male: / ho corretto a cut -f 2-
  • Ora funziona con quel file ma non ancora con un file con .png e una nuova riga subito dopo … Si consiglia di evitare di analizzare ls perché ama nascondere bene le sorprese … 🙂

Answer

Se avessi saputo che la directory avesse solo file con estensione .png, avrei semplicemente eseguito: ls | awk -F. "{print $1}"

Questo restituirà il primo “campo” per qualsiasi cosa in cui sia presente un nomefile.eestensione.

Esempio:

[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 

Commenti

  • Sfortunatamente fallirà su tutti i nomi di file con più di un ., come Image.1.png e anche su quelli con non carino nomi , con caratteri speciali allinterno. come la nuova riga o quella che utilizzerai come separatore di record (input) in awk, RS. Si consiglia di evitare di analizzare loutput ls perché ama nascondere i problemi che sorgeranno quando non te lo aspetti. Puoi leggere di più in quelli di riferimento 1 o 2 . Comunque bella lidea di usare awk … ho messo alcuni esempi in una risposta.
  • Vero, tuttavia, dato lesempio fornito da Colin, funzionerebbe benissimo. Per farlo funzionare nel caso che hai suggerito, ‘ probabilmente lo cambierei in: [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 Non sto cercando di essere difficile, ma dato il ‘ bisogno di Colin, ‘ non sono sicuro di quale sarebbe il problema sta analizzando ls.
  • scusa … mi sono appena accorto di non ‘ mostrare la directory con i file prima di sed modificare loutput di ‘ 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 devi eseguire lescape da . in \. allinterno del sed -e 's/\.png$//', ma così diventa una risposta appena scritta. 🙁 note2 puoi provare a utilizzare awk con qualcosa come ls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}' … ma avrai sempre il problema che awk non può sapere se la linea sta arrivando sta seguendo o meno una nuova riga allinterno del nome del file. Ho cercato di dire meglio nella mia risposta.
  • Grazie Hastur, mi sono perso :). Inoltre, ho abbandonato luso di awk a favore di sed in questo caso.

Answer

secondo il tuo comment “Ho un file di testo in cui sono elencati tutti i nomi senza lestensione. Voglio creare uno script PHP che confronti il file di testo con la cartella per vedere quale file manca”:

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 

e viceversa:

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) 

Risposta

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

È il metodo più accurato come evidenziato da @roaima. Senza i \.png file con escape denominati a_png.png verrebbero elencati come: a_.

Commenti

  • utilizzando ls -l, come fai, fornisce i dettagli del file, che non è ciò che lOP ha chiesto circa.

Risposta

Una semplice riga di shell (ksh, bash o zsh; non trattino):

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

Una semplice funzione (da Nessuna estensione):

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

O una funzione che rimuove qualsiasi estensione fornita (png per impostazione predefinita):

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

Utilizza come:

ne jpg 

Se loutput è un asterisco *, non esiste alcun file con tale estensione.

Risposta

Puoi provare il seguente feed awk loutput di ls il tuo superatore è “.” e poiché tutti i tuoi file avranno name.png, stampa la prima colonna:
ls | awk -F"." "{print $1}"

Answer

Se hai accesso a sed, è meglio perché rimuoverà lultima estensione del file, non importa quale sia (png, jpg, tiff, ecc …)

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

Commenti

  • Interruzioni per nomi di file come this.is.a.dotty.txt. Prova invece s/\.[^.]*$//.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *