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.