Réponses:
Dans bash ou ksh, placez les noms de fichiers dans un tableau et parcourez ce tableau dans l'ordre inverse.
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
Le code ci-dessus fonctionne également en zsh si l' ksh_arrays
option est définie (elle est en mode d'émulation ksh). Il existe une méthode plus simple dans zsh, qui consiste à inverser l'ordre des correspondances via un qualificatif glob:
for f in /var/logs/foo*.log(On); do bar $f; done
POSIX n'inclut pas de tableaux, donc si vous voulez être portable, votre seule option pour stocker directement un tableau de chaînes est les paramètres positionnels.
set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
eval "f=\${$i}"
bar "$f"
i=$((i-1))
done
i
et f
; effectuez simplement une shift
, utilisez $1
pour votre appel bar
et testez [ -z $1 ]
votre while
.
[ -z $1 ]
ni [ -z "$1" ]
les tests (que faire si le paramètre était *
, ou une chaîne vide?). Et en tout cas, cela n'aide pas ici: la question est de savoir comment boucler dans l'ordre inverse.
Essayez ceci, sauf si vous considérez les sauts de ligne comme des "personnages géniaux":
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
f
dans ma situation. Cette réponse, cependant, agit à peu près comme un remplacement sans rendez-vous pour la for
ligne ordinaire .
Si quelqu'un essaie de comprendre comment inverser l'itération sur une liste de chaînes délimitées par des espaces, cela fonctionne:
reverse() {
tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}
list="a bb ccc"
for i in `reverse $list`; do
echo "$i"
done
> ccc
> bb
> a
tac
fait partie de GNU coreutils. Mais votre solution est également bonne.
tac
. Bien que d'après le nombre de tac
réponses sans réponse ici, je suppose que OSX n'a peut-être pas de tac. Dans ce cas, utilisez une variante de la solution de @ arp - c'est plus facile à comprendre de toute façon.
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar
Devrait fonctionner comme vous le souhaitez (cela a été testé sur Mac OS X et j'ai une mise en garde ci-dessous ...).
Depuis la page de manuel pour trouver:
-print0
This primary always evaluates to true. It prints the pathname of the current file to standard output, followed by an ASCII NUL character (charac-
ter code 0).
Fondamentalement, vous trouvez les fichiers qui correspondent à votre chaîne + glob et vous terminez chacun par un caractère NUL. Si vos noms de fichiers contiennent des sauts de ligne ou d'autres caractères étranges, find devrait bien gérer cela.
tail -r
prend l'entrée standard à travers le tuyau et l'inverse (notez que toutes les entrées sont tail -r
imprimées sur stdout, et pas seulement les 10 dernières lignes, ce qui est la valeur par défaut standard. pour plus d'informations).man tail
Nous les canalisons ensuite pour xargs -0
:
-0 Change xargs to expect NUL (``\0'') characters as separators, instead of spaces and newlines. This is expected to be used in concert with the
-print0 function in find(1).
Ici, xargs s'attend à voir des arguments séparés par le caractère NUL, avec lequel vous avez passé find
et inversé tail
.
Ma mise en garde: j'ai lu que tail
cela ne fonctionne pas bien avec des chaînes terminées par null . Cela fonctionnait bien sur Mac OS X, mais je ne peux pas garantir que c'est le cas pour tous les * nix. Faites preuve de prudence.
Je dois également mentionner que GNU Parallel est souvent utilisé comme xargs
alternative. Vous pouvez également vérifier cela.
Il me manque peut-être quelque chose, alors les autres devraient sonner.
tail -r
... est-ce que je fais quelque chose de mal?
tac
comme alternative, donc j'essaierais plutôt
tail -r
est spécifique à OSX et inverse les entrées délimitées par des sauts de ligne, et non les entrées délimitées par des valeurs nulles. Votre deuxième solution ne fonctionne pas du tout (vous canalisez l'entrée vers ls
, ce qui ne fait rien); il n'y a pas de solution facile qui le rendrait fiable.
Dans votre exemple, vous bouclez sur plusieurs fichiers, mais j'ai trouvé cette question en raison de son titre plus général qui pourrait également couvrir le bouclage sur un tableau ou l'inversion en fonction d'un certain nombre de commandes.
Voici comment faire cela dans Zsh:
Si vous faites une boucle sur les éléments d'un tableau, utilisez cette syntaxe ( source )
for f in ${(Oa)your_array}; do
...
done
O
inverse l'ordre spécifié dans le drapeau suivant; a
est l'ordre normal des tableaux.
Comme l'a dit @Gilles, On
inversera l'ordre de vos fichiers globalisés, par exemple avec my/file/glob/*(On)
. C'est parce que On
c'est "l' ordre inverse des noms ".
Indicateurs de tri Zsh:
a
ordre du tableauL
longueur du fichierl
nombre de liensm
date de modificationn
prénom^o
ordre inverse ( o
est un ordre normal)O
ordre inversePour des exemples, voir https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt et http://reasoniamhere.com/2014/01/11/outrageously-useful-tips- maîtriser votre shell z /
Mac OSX ne prend pas en charge la tac
commande. La solution de @tcdyl fonctionne lorsque vous appelez une seule commande dans une for
boucle. Pour tous les autres cas, ce qui suit est le moyen le plus simple de le contourner.
Cette approche ne prend pas en charge la présence de nouvelles lignes dans vos noms de fichiers. La raison sous-jacente est que tail -r
son entrée est délimitée par des retours à la ligne.
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
Cependant, il existe un moyen de contourner la limitation de la nouvelle ligne. Si vous savez que vos noms de fichiers ne contiennent pas un certain caractère (par exemple, '='), vous pouvez utiliser tr
pour remplacer toutes les nouvelles lignes pour devenir ce caractère, puis effectuer le tri. Le résultat se présenterait comme suit:
for i in `find [directory] -name '[filename]' -print0 | tr '\n' '=' | tr '\0' '\n'
| tail -r | tr '\n' '\0' | tr '=' '\n' | xargs -0`; do [commands]; done
Remarque: en fonction de votre version de tr
, il peut ne pas être pris en charge en '\0'
tant que personnage. Cela peut généralement être résolu en changeant les paramètres régionaux en C (mais je ne me souviens pas exactement, car après l'avoir réparé une fois, cela fonctionne maintenant sur mon ordinateur). Si vous obtenez un message d'erreur et que vous ne trouvez pas la solution de contournement, veuillez la poster en tant que commentaire, afin que je puisse vous aider à le résoudre.
sort -r
avantfor
ou de la laverls -r
.