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
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 ased
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 difind
ols
, riserva spesso sorprese ben nascoste … (alcune parole e riferimenti più nella risposta). - Probabilmente sostituire
find
con qualcosa comeecho
nellultimo esempio. Non è chiaro quale sia lo scopo difind
e i risultati dipendono dalla struttura della directory (ad esempio, se hai una directoryfiles.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 als
, poichéls
presuppone che se loutput standard non è “un terminale (in questo caso” una pipe). - lopzione
-n
persed
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 dils
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 dish
per gestirli (il fatto chesh
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 unfind
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 comeImage.png.jpg.png
tagliando continuamente la chiave (.png
). In Unix sono consentiti strani nomi di file comeThe 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 dils
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 chiamatafiles.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 difind
, 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
els *.png | od -c
. Il problema di nuova riga non è un problema conls
, è ‘ è 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 analizzarels
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
.
, comeImage.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) inawk
,RS
. Si consiglia di evitare di analizzare loutputls
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 delsed -e 's/\.png$//'
, ma così diventa una risposta appena scritta. 🙁 note2 puoi provare a utilizzareawk
con qualcosa comels | 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 inveces/\.[^.]*$//
.
.
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 denominatofoo.zip
omy.picture.20160518
o semplicementemypic
.ls
e per reindirizzare loutput dils
efind
, principalmente perché la possibilità di incorrere innewline
,` 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.