La combinación de find
y ls
funciona bien para
- nombres de archivo sin saltos de línea
- cantidad no muy grande de archivos
- nombres de archivo no muy largos
La solución:
find . -name "my-pattern" -print0 |
xargs -r -0 ls -1 -t |
head -1
Vamos a desglosarlo:
Con find
podemos hacer coincidir todos los archivos interesantes como este:
find . -name "my-pattern" ...
luego usando -print0
podemos pasar todos los nombres de archivo de forma segura al ls
así:
find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t
find
adicionales Los parámetros y patrones de búsqueda se pueden agregar aquí
find . -name "my-pattern" ... -print0 | xargs -r -0 ls -1 -t
ls -t
ordenará los archivos por hora de modificación (los más nuevos primero) y los imprimirá uno por línea. Puedes usar -c
para ordenar por tiempo de creación. Nota :esto se romperá con los nombres de archivo que contengan líneas nuevas.
Finalmente head -1
nos obtiene el primer archivo en la lista ordenada.
xargs
use los límites del sistema para el tamaño de la lista de argumentos. Si este tamaño excede, xargs
llamará al ls
varias veces. Esto romperá la clasificación y probablemente también la salida final. Ejecutar
xargs --show-limits
para comprobar los límites de su sistema.
Nota 2: usa find . -maxdepth 1 -name "my-pattern" -print0
si no desea buscar archivos a través de subcarpetas.
Nota 3: Como señaló @starfry - -r
argumento para xargs
está impidiendo la llamada de ls -1 -t
, si ningún archivo coincide con el find
. Gracias por la sugerencia.
El ls
el comando tiene un parámetro -t
para ordenar por tiempo. Luego puede tomar el primero (el más nuevo) con head -1
.
ls -t b2* | head -1
Pero cuidado:por qué no deberías analizar la salida de ls
Mi opinión personal:analizar ls
solo es peligroso cuando los nombres de archivo pueden contener caracteres divertidos como espacios o saltos de línea. Si puede garantizar que los nombres de los archivos no contendrán caracteres divertidos, analice ls
es bastante seguro.
Si está desarrollando un script que está destinado a ser ejecutado por muchas personas en muchos sistemas en muchas situaciones diferentes, le recomiendo no analizar ls
.
He aquí cómo hacerlo "bien":¿Cómo puedo encontrar el archivo más reciente (más nuevo, más antiguo, más antiguo) en un directorio?
unset -v latest
for file in "$dir"/*; do
[[ $file -nt $latest ]] && latest=$file
done
Esta es una posible implementación de la función Bash requerida:
# 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
}
Solo usa componentes integrados de Bash y debe manejar archivos cuyos nombres contengan líneas nuevas u otros caracteres inusuales.