web-dev-qa-db-fra.com

Comment exécuter plusieurs commandes après xargs -0?

find . -name "filename including space" -print0 | xargs -0 ls -aldF > log.txt
find . -name "filename including space" -print0 | xargs -0 rm -rdf

Est-il possible de combiner ces deux commandes en une seule pour qu'une seule recherche soit effectuée au lieu de 2?

Je sais que pour xargs -I il peut y avoir des moyens de le faire, ce qui peut conduire à des erreurs lors de la poursuite des noms de fichiers, y compris les espaces. Tout conseil est très apprécié.

24
Richard Chen

Si vous voulez simplement éviter de faire plusieurs fois le find, vous pouvez faire un tee juste après le find, en enregistrant la sortie find dans un fichier, puis exécutez les lignes comme:

find . -name "filename including space" -print0 | tee my_teed_file | xargs -0 ls -aldF > log.txt
cat my_teed_file | xargs -0 rm -rdf 

Une autre façon d'accomplir cette même chose (si c'est vraiment ce que vous voulez accomplir) est de stocker la sortie du find dans une variable (en supposant que ce n'est pas TB de données):

founddata=`find . -name "filename including space" -print0`
echo "$founddata" | xargs -0 ls -aldF > log.txt
echo "$founddata" | xargs -0 rm -rdf
16
Jonathan M
find . -name "filename including space" -print0 | 
  xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt; rm -rdf {}'
48
glenn jackman

Je crois que toutes ces réponses ont désormais permis de résoudre ce problème. Et j'ai essayé les 2 solutions de Jonathan et la voie de Glenn, qui fonctionnaient toutes très bien sur mon Mac OS X. La méthode de mouviciel n'a pas fonctionné sur mon OS peut-être pour des raisons de configuration. Et je pense que c'est similaire à la deuxième méthode de Jonathan (je peux me tromper).

Comme mentionné dans les commentaires sur la méthode de Glenn, un petit ajustement est nécessaire. Voici donc la commande que j'ai essayée qui fonctionnait parfaitement pour info:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} | tee -a log.txt ; rm -rdf {}'

Ou mieux comme suggéré par Glenn:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt ; rm -rdf {}'
5
Richard Chen

Tant que vous n'avez pas de nouvelle ligne dans vos noms de fichiers, vous n'avez pas besoin de -print0 pour GNU Parallel:

find . -name "My brother's 12\" records" | parallel ls {}\; rm -rdf {} >log.txt

Regardez la vidéo d'introduction pour en savoir plus: http://www.youtube.com/watch?v=OpaiGYxkSuQ

4
Ole Tange

Juste une variation de l'approche xargs sans cette horrible -print0 et xargs -0, voici comment je procéderais:

ls -1 *.txt  | xargs --delimiter "\n" --max-args 1 --replace={} sh -c 'cat {}; echo "\n"'

Notes de bas de page:

  • Oui, je sais que les nouvelles lignes peuvent apparaître dans les noms de fichiers, mais qui, dans leur bon sens, le ferait
  • Il existe de courtes options pour xargs mais pour la compréhension du lecteur, j'ai utilisé les longues.
  • J'utiliserais ls -1 quand je veux un comportement non récursif plutôt que find -maxdepth 1 -iname "*.txt" qui est un peu plus verbeux.
2
Sridhar Sarnobat

Je suis en retard à la fête, mais il y a une autre solution qui n'a pas été abordée ici: les fonctions définies par l'utilisateur. Mettre plusieurs instructions sur une seule ligne est compliqué et peut être difficile à lire/à maintenir. La boucle for ci-dessus évite cela, mais il est possible de dépasser la longueur de la ligne de commande.

Voici une autre façon (non testée).

function processFiles {
  ls -aldF "$@"
  rm -rdf "$@"
}
export -f processFiles

find . -name "filename including space"` -print0 \
  | xargs -0 bash -c processFiles dummyArg > log.txt

C'est assez simple, sauf pour le "dummyArg" qui m'a donné beaucoup de chagrin. Lorsque vous exécutez bash de cette manière, les arguments sont lus dans

"$0" "$1" "$2"  ....

au lieu de l'attendu

"$1" "$2" "$3"    ....

Puisque processFiles {} s'attend à ce que le premier argument soit "$ 1", nous devons insérer une valeur fictive dans "$ 0".

Footnontes:

  1. J'utilise certains éléments de la syntaxe bash (par exemple "export -f"), mais je pense que cela s'adaptera à d'autres shells.
  2. La première fois que j'ai essayé cela, je n'ai pas ajouté d'argument factice. Au lieu de cela, j'ai ajouté "$" aux lignes d'argument à l'intérieur de ma fonction (par exemple ls -aldf "$ 0" "$ @"). Mauvaise idée. Mis à part les problèmes stylistiques, il se casse lorsque la commande "find" ne renvoie rien. Dans ce cas, $ 0 est défini sur "bash", l'utilisation de l'argument factice à la place évite tout cela.
1
Phil Freed

Vous pouvez exécuter plusieurs commandes après find en utilisant for au lieu de xargs:

IFS=$'\n'
for F in `find . -name "filename including space"`
do
    ls -aldF $F > log.txt
    rm -rdf $F
done

IFS définit le séparateur de champ interne, qui est par défaut <space><tab> <newline>. Si vos noms de fichiers peuvent contenir des espaces, il est préférable de les redéfinir comme ci-dessus.

1
ericbn

Une autre solution:

find . -name "filename including space" -print0 \
| xargs -0 -I FOUND echo "$(ls -aldF FOUND > log.txt ; rm -rdf FOUND)"
0
mouviciel