La combinazione di find
e ls
funziona bene per
- nomi di file senza newline
- quantità di file non molto grande
- nomi di file non molto lunghi
La soluzione:
find . -name "my-pattern" -print0 |
xargs -r -0 ls -1 -t |
head -1
Analizziamolo:
Con find
possiamo abbinare tutti i file interessanti come questo:
find . -name "my-pattern" ...
poi usando -print0
possiamo passare tutti i nomi di file in modo sicuro al ls
come questo:
find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t
ulteriori find
parametri di ricerca e modelli possono essere aggiunti qui
find . -name "my-pattern" ... -print0 | xargs -r -0 ls -1 -t
ls -t
ordinerà i file in base all'ora di modifica (prima i più recenti) e li stamperà uno per riga. Puoi usare -c
per ordinare in base all'ora di creazione. Nota :questo si romperà con nomi di file contenenti newline.
Infine head -1
ci fornisce il primo file nell'elenco ordinato.
Nota: xargs
utilizzare i limiti di sistema alla dimensione dell'elenco degli argomenti. Se questa dimensione supera, xargs
chiamerà ls
più volte. Ciò interromperà l'ordinamento e probabilmente anche l'output finale. Esegui
xargs --show-limits
per controllare i limiti del tuo sistema.
Nota 2: usa find . -maxdepth 1 -name "my-pattern" -print0
se non vuoi cercare i file nelle sottocartelle.
Nota 3: Come sottolineato da @starfry - -r
argomento per xargs
impedisce la chiamata di ls -1 -t
, se nessun file corrisponde a find
. Grazie per il suggerimento.
Il ls
Il comando ha un parametro -t
ordinare per tempo. Puoi quindi prendere il primo (il più recente) con head -1
.
ls -t b2* | head -1
Ma attenzione:perché non dovresti analizzare l'output di ls
La mia opinione personale:analizzare ls
è pericoloso solo quando i nomi dei file possono contenere caratteri divertenti come spazi o newline. Se puoi garantire che i nomi dei file non conterranno caratteri divertenti, allora analizza ls
è abbastanza sicuro.
Se stai sviluppando uno script che deve essere eseguito da molte persone su molti sistemi in molte situazioni diverse, ti consiglio vivamente di non analizzare ls
.
Ecco come farlo "correttamente":come posso trovare il file più recente (il più recente, il più vecchio, il più vecchio) in una directory?
unset -v latest
for file in "$dir"/*; do
[[ $file -nt $latest ]] && latest=$file
done
Questa è una possibile implementazione della funzione Bash richiesta:
# Print the newest file, if any, matching the given pattern
# Example usage:
# newest_matching_file 'b2*'
# WARNING: Files whose names begin with a dot will not be checked
function newest_matching_file
{
# Use ${1-} instead of $1 in case 'nounset' is set
local -r glob_pattern=${1-}
if (( $# != 1 )) ; then
echo 'usage: newest_matching_file GLOB_PATTERN' >&2
return 1
fi
# To avoid printing garbage if no files match the pattern, set
# 'nullglob' if necessary
local -i need_to_unset_nullglob=0
if [[ ":$BASHOPTS:" != *:nullglob:* ]] ; then
shopt -s nullglob
need_to_unset_nullglob=1
fi
newest_file=
for file in $glob_pattern ; do
[[ -z $newest_file || $file -nt $newest_file ]] \
&& newest_file=$file
done
# To avoid unexpected behaviour elsewhere, unset nullglob if it was
# set by this function
(( need_to_unset_nullglob )) && shopt -u nullglob
# Use printf instead of echo in case the file name begins with '-'
[[ -n $newest_file ]] && printf '%s\n' "$newest_file"
return 0
}
Usa solo i built-in di Bash e dovrebbe gestire i file i cui nomi contengono newline o altri caratteri insoliti.