Come utilizzare il comando Trova per elencare i nomi dei file ma non il percorso?
Ho controllato alcune risposte online, ma non funzionano quando c'è un -name
parametro nel comando (forse sto facendo qualcosa di sbagliato, non sono sicuro). Quello che mi piacerebbe fare è elencare solo i nomi di file (non la directory / percorso) e, per complicare di più, ho lo stesso nome di file con un'estensione diversa, quindi devo filtrare il risultato usando -name
e -o
, il problema sono i suggerimenti che ho visto usare -printf
o basename
, e quelli non funzionano bene quando c'è -name *.txt -o name *.pdf
. C'è un altro modo per risolvere questo problema?
Esempio dei miei file:
/dir1/dir2/dir3/dir4/
/file1.txt
/file1.pdf
/file1.ods ...etc.
Sono interessato solo a elencare uno o più tipi di file per elenco (utilizzando -name
per filtrare i risultati.
È possibile find
eseguirlo utilizzando solo 1 comando o devo farlo in 2 passaggi (salvando il risultato in un file temporaneo, quindi filtrando / rimuovendo la directory dal file temporaneo)? Il risultato che sto cercando di ottenere è un file di testo con il nome del file per riga:
file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.
Il comando che stavo usando è
find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"
Sto usando GNU find.
Aggiornare
Si è scoperto che devo mettere \(...\)
, come ricordato da αғsнιη
Risposte
Quando si utilizzano più espressioni in modalità OR logico con -o
è necessario racchiuderle tutte all'interno \( ... \)
, altrimenti il risultato dell'ultima espressione viene sempre rispettato; e -printf '%f\n'
viene utilizzato per stampare il nome dei file solo con qualsiasi directory principale rimossa.
find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'
vedere man findnella sezione OPERATORI su ( expr )
:
OPERATORI
...(espr)
Forza la precedenza. Poiché le parentesi sono speciali per la shell, normalmente sarà necessario citarle.
quindi puoi usare \( ... \)
o '(' ... ')'
(gli spazi bianchi dopo e prima delle parentesi sono importanti) per sfuggirli.
Come già accennato, devi raggruppare i tuoi -name
test tra parentesi. Queste parentesi devono essere evase \( ... \)
o citate come ad esempio '(' ... ')'
per proteggerle dalla shell (dove altrimenti designerebbero una subshell).
Usando lo standard find
e rendendo leggermente più semplice la gestione dei suffissi del nome del file:
set -- txt pdf ods
for suffix do
set -- "$@" -o -name "*.$suffix"
shift
done
shift
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;
Questo prima imposta i parametri posizionali sull'elenco dei suffissi dei nomi dei file che vorremmo vedere (questo potrebbe anche essere preso dalla riga di comando se si tratta di uno script) e costruisce l'elenco OR dei -name
test. Questo viene quindi utilizzato nella find
riga di comando.
Il find
comando stesso chiama quindi l' basename
utilità per ogni nome trovato.
In alternativa, potremmo invece utilizzare una sostituzione di parametro per rimuovere tutto tranne il componente del nome file di ciascun percorso, ma per farlo dobbiamo passare i nomi di percorso a uno sh -c
script inline :
# [...] as before [...]
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
for pathname do
printf "%s\n" "${pathname##*/}"
done' sh {} +
Mi aspetto che questo venga eseguito più velocemente della variazione utilizzando basename
, almeno se ci sono molti nomi di file da gestire, sebbene con GNU basename
di coreutils, potresti usare -a
o mi --multiple
piace così:
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +
Questo chiamerebbe il basename
minor numero di volte possibile. Ma poi di nuovo, se hai installato coreutils, potresti avere anche findutils, con GNU find
, e potresti usare -printf '%f\n'
per fare la stessa cosa.