La combinaison de find
et ls
fonctionne bien pour
- noms de fichiers sans nouvelle ligne
- pas une très grande quantité de fichiers
- des noms de fichiers pas très longs
La solution :
find . -name "my-pattern" -print0 |
xargs -r -0 ls -1 -t |
head -1
Décomposons-le :
Avec find
nous pouvons faire correspondre tous les fichiers intéressants comme ceci :
find . -name "my-pattern" ...
puis en utilisant -print0
nous pouvons transmettre tous les noms de fichiers en toute sécurité au ls
comme ceci :
find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t
find
supplémentaire les paramètres de recherche et les modèles peuvent être ajoutés ici
find . -name "my-pattern" ... -print0 | xargs -r -0 ls -1 -t
ls -t
triera les fichiers par heure de modification (le plus récent en premier) et les imprimera un à la ligne. Vous pouvez utiliser -c
pour trier par heure de création. Remarque :cela rompra avec les noms de fichiers contenant des retours à la ligne.
Enfin head -1
nous obtient le premier fichier de la liste triée.
Remarque : xargs
utiliser les limites du système à la taille de la liste d'arguments. Si cette taille dépasse, xargs
appellera le ls
plusieurs fois. Cela cassera le tri et probablement aussi la sortie finale. Exécuter
xargs --show-limits
pour vérifier les limites de votre système.
Remarque 2 : utilisez find . -maxdepth 1 -name "my-pattern" -print0
si vous ne souhaitez pas rechercher des fichiers dans des sous-dossiers.
Remarque 3 : Comme l'a souligné @starfry - -r
argument pour xargs
empêche l'appel du ls -1 -t
, si aucun fichier ne correspond au find
. Merci pour la suggestion.
Le ls
la commande a un paramètre -t
trier par temps. Vous pouvez ensuite saisir le premier (le plus récent) avec head -1
.
ls -t b2* | head -1
Mais attention :pourquoi vous ne devriez pas analyser la sortie de ls
Mon avis personnel :parsing ls
n'est dangereux que lorsque les noms de fichiers peuvent contenir des caractères amusants comme des espaces ou des retours à la ligne. Si vous pouvez garantir que les noms de fichiers ne contiendront pas de caractères amusants, analysez ls
est tout à fait sûr.
Si vous développez un script destiné à être exécuté par de nombreuses personnes sur de nombreux systèmes dans de nombreuses situations différentes, je vous recommande fortement de ne pas analyser ls
.
Voici comment le faire "correctement" :Comment puis-je trouver le dernier fichier (le plus récent, le plus ancien, le plus ancien) dans un répertoire ?
unset -v latest
for file in "$dir"/*; do
[[ $file -nt $latest ]] && latest=$file
done
Voici une implémentation possible de la fonction Bash requise :
# 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
}
Il utilise uniquement les commandes intégrées de Bash et doit gérer les fichiers dont les noms contiennent des retours à la ligne ou d'autres caractères inhabituels.