INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`
Je voulais exécuter la deuxième commande ( head -1
) uniquement si la première commande réussit. Comment puis-je améliorer cette commande?
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`
Je voulais exécuter la deuxième commande ( head -1
) uniquement si la première commande réussit. Comment puis-je améliorer cette commande?
Réponses:
Essaye ça:
INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml | head -1 | xargs -r basename`
Si vous passez xargs
l' -r
indicateur, il ne s'exécutera que basename
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 rediriger ls
le flux stderr vers /dev/null
.
INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename`
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.
input_file=$(ls -rt "$my_dir"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename)
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.
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 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):
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_name
tableau 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_name
else
echo >&2 No match
fi
Recherchez le dernier fichier modifié dans un répertoire:
latest() {
local file path=${1:-.} ext=${2-} latest
for file in "${path%/}"/*"$ext"; do
[[ $file -nt $latest ]] && latest=$file
done
[[ $latest ]] && printf '%s\n' "$latest"
}
Usage: latest [directory/path/ [.extension]]
Au lieu d'appeler à basename
, utilisez l'expansion des paramètres.
in_file=$(latest in/my/dir .xml)
base_fn=${in_file##*/} base_fn=${base_fn%.*}
Dans un répertoire avec ces contenus:
foo.xml bar.xml baz.xml newest.xml
Le contenu de la variable base_fn serait: newest
Pour l'utiliser correctement afin de répondre à l'objectif de votre demande:
check_dir=/path/to/check
check_ext=.xml
if 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" >&2
fi
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ée oldest
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.
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 pour ls
y obtenir le même comportement).
Je pense que la meilleure option ici est:
ls -rf $MY_DIR/FILE.*.xml
if [ $? -eq 0 ]; then
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml|head -1|xargs basename `
else
echo "Error!"
fi
s'il n'y a pas de fichier alors le code retour de ls est 2 mais s'il trouve un fichier sera 0.
ls
n'échouera pas.