Pourquoi cette commande xargs ne fonctionne-t-elle pas?

14

Je voulais supprimer toutes les extensions .sh, j'ai fait ceci:

ls *.sh | xargs -I {} mv {} `basename {} .sh`

Cependant, cela ne fonctionne pas, il se comporte comme basenameun nom de fichier sans changement.

Pourquoi se comporte-t-il ainsi?

Par exemple, cela fonctionne:

ls *.sh | xargs -I {} echo `basename {}.jpg .jpg`;

MODIFIER :

Solution: un guillemet simple empêche l' `basename ...`évaluation par le shell avant l'exécution de la commande.

ls *.sh | xargs -I {}  sh -c 'mv {} `basename {} .sh`'
majkinetor
la source

Réponses:

12

Parce que la commande basename est exécutée avant l'exécution du pipeline. Pour que cela fonctionne, vous avez besoin de xargs pour exécuter basename et vous pouvez le faire avec sh -c, par exemple:

ls *.sh | xargs -L1 sh -c 'basename $1 .sh' dummy

Remarques:

  • Si vous ne dites pas xargsoù insérer les noms de fichiers, ils seront ajoutés à la fin de la ligne de commande.
  • Vous devez utiliser le -L1commutateur ou son équivalent, donc xargsne transmet qu'un seul argument à sh.
  • L'utilisation de la sortie de lspeut avoir des effets indésirables .

Éditer

Suppression des options obsolètes, merci TechZilla

Thor
la source
3
Votre premier point est incorrect, sauf si vous vouliez dire qu'il s'agit par défaut de l' -ioption, mais ces options «classiques» ont été dépréciées. Par exemple, pour utiliser une seule option / ligne, la nouvelle page de manuel POSIX recommande -L1. Pour appeler l'ancien comportement de -i, la page recommande l' -I'{}'option.
JM Becker
Donc, il s'agit en fait de symboles "" à la place "". Je suppose que `` empêche l'évaluation shell de ``. Voir mes modifications.
majkinetor
@TechZilla: merci pour les corrections. @majkinetor: oui et non, vous devez retarder l'évaluation, mais je ne pense pas que vous puissiez utiliser des backticks (`).
Thor
1
@majkinetor: ah, je vois ce que tu veux dire maintenant. Pour renommer des fichiers de cette manière , je préfère utiliser rename, par exemple: rename 's/\.sh//' *.sh. Essayez d'abord avec un essai à sec ( -n).
Thor
1
@majkinetor: renamefonctionne très bien et assez simple, mais n'oubliez pas que c'est très spécifique à la distribution. Les distributions basées sur RHEL et Debian fournissent des renamecommandes différentes , il faut donc garder cela à l'esprit lors de la création de scripts de distribution croisée.
JM Becker
4

Je ne suis pas sûr de votre question, demandez-vous pourquoi votre première ligne ne fonctionne pas? Ou recherchez-vous une méthode appropriée pour renommer tous les fichiers .sh?

En supposant que c'est la méthode la plus propre, je préfère préparer les options de commande avant xargs. Pour supprimer une extension de fichier .sh, je considère souvent cette approche,

 find -maxdepth 1 -type f -iname '*.sh'  | sed 'p;s_.sh$__' | xargs -L2 mv
JM Becker
la source