La modification de chaîne de remplacement dans xargs
Quand je suis en utilisant xargs
parfois je n'ai pas besoin d'utiliser explicitement le remplacement de la chaîne:
find . -name "*.txt" | xargs rm -rf
Dans d'autres cas, je tiens à préciser que le remplacement de la chaîne, pour faire des choses comme:
find . -name "*.txt" | xargs -I '{}' mv '{}' /foo/'{}'.bar
La commande précédente serait de déplacer tous les fichiers texte dans le répertoire courant dans /foo
et il va ajouter l'extension bar
à tous les fichiers.
Si au lieu d'ajouter du texte à la chaîne de remplacement, j'ai voulu modifier cette chaîne pour que je puisse insérer du texte entre le nom et l'extension des fichiers, comment pourrais-je le faire? Par exemple, disons que je veux faire la même chose que dans l'exemple précédent, mais les fichiers doivent être renommés/déplacé de <name>.txt
à /foo/<name>.bar.txt
(au lieu de /foo/<name>.txt.bar
).
Mise à JOUR: j'ai réussi à trouver une solution:
find . -name "*.txt" | xargs -I{} \
sh -c 'base=$(basename $1) ; name=${base%.*} ; ext=${base##*.} ; \
mv "$1" "foo/${name}.bar.${ext}"' -- {}
Mais je me demande si il y a un court/une meilleure solution.
- Non, sauf que je voudrais utiliser plus citant
mv "$1" "foo/${name}.bar.${ext}"
et vous pourriez fairebasename
comme ceci:base=${1##*/}
. Vous devriez poster votre solution comme une réponse et de l'accepter. - Merci pour votre commentaire! Je vais attendre un peu plus, juste pour voir si quelqu'un arrive avec un peu de fantaisie chose, sinon je vais répondre à la question moi-même.
- Je pense que si votre nom de fichier est la dernière chose sur la ligne, vous n'avez pas besoin de l'-I{} ni {} dans la ligne de commande. (À noter que le but même de xargs est de groupe, si vous NE voulez PAS plusieurs choses à la fin de 1 xargs l'argument de l'invocation, vous avez besoin "-l 1" (ou-L 1 pour certaines versions de xargs). -I{} implique -l 1, donc c'est pour ça que fonctionne également ici).
- Le
sh -c
a été la clé pour moi! Merci! D'autre ma coupe/sed commande enecho {}|sed '...'
n'a pas été exécutée
Vous devez vous connecter pour publier un commentaire.
Dans de tels cas, un
while
boucle serait plus lisible:Noter que vous pouvez trouver des fichiers avec le même nom dans différents sous-répertoires. Êtes-vous OK avec des doublons sur-écrit par
mv
?find . -name "*.txt" -print0 | while read -r -d '' pathname; do ...
--max-procs
.La commande suivante génère la commande déplacer avec xargs, remplace la deuxième occurrence de '.' par '.bar.', puis exécute les commandes avec bash, fonctionne sur mac OSX.
Il est possible de le faire en une seule passe (testé sous GNU) en évitant l'utilisation de la variable temporaire affectations
Si vous avez GNU Parallèle http://www.gnu.org/software/parallel/ installé, vous pouvez le faire:
Regarder les vidéos d'intro pour GNU Parallèles pour en savoir plus:
https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
xargs
, il est beaucoup plus puissant et flexible. Comme pour son installation, je vous suggère fortement d'utiliser la distribution de votre gestionnaire de packages (commesudo apt-get install parallel
) ou en parallèle est recommandé procédure d'installation (comme par git.savannah.gnu.org/cgit/parallel.git/tree/README):(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash
pi.dk
? Pourquoi devrais-je faire confiance à ce domaine?gnu.org
est au moins plus digne de confiance. Mais ni l'URL est l'utilisation de TLS, et plus important encore, ni l'un vérifie une signature cryptographique de ce qui est téléchargé. La seule solution à recommander estapt-get
.wget ... && chmod +x
wget ...
parce que c'est dangereux pour de nombreuses raisons. Cela revient à dire à un utilisateur de Windows pour exécuter uneexe
aléatoire à partir d'un site web sans recherche de virus. Suffit de dire non.pi.dk
, si seulement pour un accès HTTPS. Les instructions officielles pourrait alors suggérerwget && chmod
sur le installer script (au lieu de directement sur le parallèle de script) afin d'éviter le pipe-à-shell. Mais c'est une tâche pour Ole Tange, en parallèle du responsable 🙂Si vous êtes autorisé à utiliser autre chose que bash/sh, ET ce n'est qu'une fantaisie "mv"... vous pouvez essayer le vénérable "rename.pl de script". - Je l'utiliser sur Linux et cygwin sous windows tout le temps.
http://people.sc.fsu.edu/~jburkardt/pl_src/rename/rename.html
Vous pouvez également utiliser un "-p" paramètre rename.pl pour l'avoir à vous dire ce qu'il AURAIT FAIT, sans le faire réellement.
J'ai juste essayé le suivant dans mon c:/bin (cygwin/environnement windows). J'ai utilisé l'option "-p", donc il crache ce qu'il aurait fait. Cet exemple juste divise la base et l'extension, et ajoute une chaîne de caractères entre eux.
mv
exemple est juste un exemple, bien que. Je fais face à la nécessité de faire quelque chose de similaire dans beaucoup d'autres situations, donc je suppose querename.pl
ne fonctionnerait pas pour ces cas.Vous pouvez utiliser
rename
utilitaire, par exemple:Indice: Le remplacement de la syntaxe est similaire à
sed
ouvim
.Puis déplacez les fichiers à certains répertoire cible en utilisant
mv
:Faire renommer les fichiers dans les sous-répertoires basés sur une certaine partie de leur nom, vérifier:
Test:
Inspiré par une réponse par @justaname ci-dessus, cette commande qui intègre Perl one-liner va le faire:
find ./-name \*.txt | perl -p -e 's/^(.*\/(.*)\.txt)$/mv $1 .\/foo\/$2.bar.txt/' | bash
Ajoutant que le article de wikipedia est étonnamment instructif
par exemple: