Notez également que j'ai ajouté des guillemets autour $MY_DIR. De cette façon, la commande n'échouera pas si $MY_DIRcontient des espaces.
Si vous utilisez un shell moderne tel que bash, vous devez utiliser un $( )shell de capture au lieu de backticks. Vous devriez également envisager de changer le style de vos variables. Vous devez généralement éviter d'utiliser des noms de variables en majuscules dans les scripts. Ce style est généralement réservé aux variables réservées et environnementales.
input_file=$(ls -rt "$my_dir"/FILE.*.xml 2>/dev/null | head -1| xargs -r basename)
En fait: ça ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basenamemarche.
Mel Boyce
@MelBoyce: J'ai ajouté cela à ma réponse. Merci.
ls est un outil pour consulter de manière interactive les informations sur les fichiers. Sa sortie est formatée pour les humains et provoquera des bugs dans les scripts. Utilisez des globes ou recherchez plutôt. Comprenez pourquoi: mywiki.wooledge.org/ParsingLs
cinelli
@cinelli: C'est vrai. Je répondais juste à la question.
9
Dans un pipeline, toutes les commandes sont démarrées et exécutées simultanément, pas l'une après l'autre. Vous devez donc stocker la sortie quelque part.
if ls_output=$(ls -rtd --"$MY_DIR"/FILE.*.xml);then
first_file=$(printf '%s\n'"$ls_output"| head -n 1)
first_file_name=$(basename --"$first_file")fi
Notez qu'il suppose que les noms de fichiers ne contiennent pas de caractères de nouvelle ligne. L'utilisation xargssignifierait également des problèmes avec les caractères vides, les guillemets simples et doubles et les barres obliques inverses. Laisser des variables sans guillemets signifierait des problèmes d'espace, de tabulation et de caractères génériques. Oublier --signifierait des problèmes avec les noms de fichiers commençant par -.
Pour obtenir le nom de base du fichier le plus ancien avec zshsans aucune de ces restrictions sur les caractères (évite également le problème de la taille limitée des arguments d'une commande):
first_file_name=($MY_DIR/FILE.*.xml(Om[1]:t))
S'il n'y a pas de correspondance, cette commande échouera et abandonnera le script. Vous pouvez également faire:
first_file_name=($MY_DIR/FILE.*.xml(NOm[1]:t))
Dans ce cas, le first_file_nametableau contiendra 1 élément s'il y a correspondance ou 0 sinon. Vous pouvez alors faire:
if(($#first_file_name)); then
printf 'Match: %s\n' $first_file_nameelse
echo >&2No matchfi
Pour l'utiliser correctement afin de répondre à l'objectif de votre demande:
check_dir=/path/to/check
check_ext=.xmlif in_file=$(latest "$check_dir""$check_ext");then
base_fn=${in_file##*/} base_fn=${base_fn%.*}else
printf '%s\n'"No file found in $check_dir">&2fi
EDIT: après examen de la question, j'ai réalisé que la lscommande en question recherche le fichier le plus ancien dans un répertoire. cette même fonction pourrait être renommée oldestet avoir [[ $file -ot $oldest ]] && oldest=$filepour obtenir le même effet. excuses pour toute confusion.
la chose importante à noter est que vous ne devez absolument, en aucun cas dans l’humanité, analyser la sortie de ls. jamais.
Notez que contrairement aux lsapproches basées sur des liens symboliques, s'il y a des liens symboliques, le temps de modification de la cible des liens symboliques sera pris en compte (ajoutez l' -Loption pour lsy obtenir le même comportement).
Au lieu de comparer $?contre 0, vous pouvez le faire: if ls -rf $MY_DIR/FILE.*.xml ; then.
Vous pouvez également rediriger la sortie de la première commande vers /dev/null. ls -rf $MY_DIR/FILE.*.xml &> /dev/null. De cette façon, l'utilisateur ne verra pas la sortie supplémentaire.
ls
n'échouera pas.Réponses:
Essaye ça:
Si vous passez
xargs
l'-r
indicateur, il ne s'exécutera quebasename
s'il lit au moins un élément de l'entrée standard (head -1
).head -1
s'exécutera mais vous ne verrez ni n'en capturerez aucune sortie.De plus, si vous ne voulez pas que l'utilisateur voie une sortie d'erreur
ls
, vous pouvez redirigerls
le flux stderr vers/dev/null
.Notez également que j'ai ajouté des guillemets autour
$MY_DIR
. De cette façon, la commande n'échouera pas si$MY_DIR
contient des espaces.Si vous utilisez un shell moderne tel que bash, vous devez utiliser un
$( )
shell de capture au lieu de backticks. Vous devriez également envisager de changer le style de vos variables. Vous devez généralement éviter d'utiliser des noms de variables en majuscules dans les scripts. Ce style est généralement réservé aux variables réservées et environnementales.la source
ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basename
marche.Dans un pipeline, toutes les commandes sont démarrées et exécutées simultanément, pas l'une après l'autre. Vous devez donc stocker la sortie quelque part.
Notez qu'il suppose que les noms de fichiers ne contiennent pas de caractères de nouvelle ligne. L'utilisation
xargs
signifierait également des problèmes avec les caractères vides, les guillemets simples et doubles et les barres obliques inverses. Laisser des variables sans guillemets signifierait des problèmes d'espace, de tabulation et de caractères génériques. Oublier--
signifierait des problèmes avec les noms de fichiers commençant par-
.Pour obtenir le nom de base du fichier le plus ancien avec
zsh
sans aucune de ces restrictions sur les caractères (évite également le problème de la taille limitée des arguments d'une commande):S'il n'y a pas de correspondance, cette commande échouera et abandonnera le script. Vous pouvez également faire:
Dans ce cas, le
first_file_name
tableau contiendra 1 élément s'il y a correspondance ou 0 sinon. Vous pouvez alors faire:la source
Recherchez le dernier fichier modifié dans un répertoire:
Usage:
latest [directory/path/ [.extension]]
Au lieu d'appeler à
basename
, utilisez l'expansion des paramètres.Dans un répertoire avec ces contenus:
Le contenu de la variable base_fn serait:
newest
Pour l'utiliser correctement afin de répondre à l'objectif de votre demande:
EDIT: après examen de la question, j'ai réalisé que la
ls
commande en question recherche le fichier le plus ancien dans un répertoire. cette même fonction pourrait être renomméeoldest
et avoir[[ $file -ot $oldest ]] && oldest=$file
pour obtenir le même effet. excuses pour toute confusion.la chose importante à noter est que vous ne devez absolument, en aucun cas dans l’humanité, analyser la sortie de ls. jamais.
la source
ls
approches basées sur des liens symboliques, s'il y a des liens symboliques, le temps de modification de la cible des liens symboliques sera pris en compte (ajoutez l'-L
option pourls
y obtenir le même comportement).Je pense que la meilleure option ici est:
s'il n'y a pas de fichier alors le code retour de ls est 2 mais s'il trouve un fichier sera 0.
la source
$?
contre0
, vous pouvez le faire:if ls -rf $MY_DIR/FILE.*.xml ; then
./dev/null
.ls -rf $MY_DIR/FILE.*.xml &> /dev/null
. De cette façon, l'utilisateur ne verra pas la sortie supplémentaire.