Vous étiez très proche.
seq 15 -1 1 | xargs [email protected] sh -c 'mv @_* @'
Vous devez retarder l'interprétation (expansion) du *
jusqu'après le @
substitution a eu lieu. (Mais vous avez déjà compris que c'était ça le problème, n'est-ce pas ?)
On m'a conseillé de ne jamais intégrer un nom de fichier inconnu (ou une autre chaîne de substitution) directement dans une ligne de commande shell. L'exemple ci-dessus est probablement assez sûr, car vous savez quelles seront les chaînes —15
, 14
, …, 3
, 2
et 1
. Mais utiliser l'exemple ci-dessus comme modèle pour des commandes plus complexes peut être dangereux. Un arrangement plus sûr serait
seq 15 -1 1 | xargs [email protected] sh -c 'mv -- "$1"_* "$1"' x-sh @
où x-sh
est une chaîne semi-arbitraire qui sera utilisée pour étiqueter tous les messages d'erreur émis par le shell invoqué. Ceci est équivalent à mon premier exemple, sauf que plutôt que d'intégrer les chaînes (représentées par @
) directement dans la commande shell, il les injecte en fournissant le @
en tant qu'argument du shell, puis en les référençant en tant que "$1"
.
PS Vous avez suggéré d'exécuter le seq
commande en sens inverse(seq 15 -1 1
, qui génère 15
, 14
, …, 3
, 2
, 1
plutôt que 1
, 2
, 3
, …, 14
, 15
) et personne ne l'a mentionné. Ce serait une partie importante de la réponse si vos noms de fichiers étaient comme 1foo.txt
, 2bar.asc
, et 13test.png
, etc. (avec différents caractères apparaissant après le nombre, plutôt que toujours _
). Dans ce cas, la commande serait mv "$1"* "$1"
(sans le _
), et, si vous avez fait 1
d'abord, puis la commande mv 1* 1
balayerait tous les 10quick*
, 11brown*
, 12fox*
, etc., fichiers, avec le 1foo*
des dossiers. Mais
seq 1 15 | xargs [email protected] sh -c 'mv -- "$1"_* "$1"' x-sh @
devrait être sûr.
P.P.S. Le seq
La commande n'est pas spécifiée par POSIX. L'expansion de l'accolade n'est pas non plus dans la coque. Une solution compatible POSIX peut être construite en combinant la réponse de Grawity à cette question avec cette autre réponse d'Adam Katz :
i=1
while [ "$i" -le 15 ]
do
mv -- "${i}"_* "$i"
i=$((i+1))
done
P.P.P.S. Ce n'est pas critique lorsque vous savez que les noms de fichiers commencent par des caractères alphanumériques (c'est-à-dire des lettres et des chiffres), mais, dans des cas plus généraux, vous devez utiliser --
entre le nom de la commande et les arguments. Cela améliore la gestion des noms de fichiers commençant par un tiret. Le --
indique à la commande de traiter l'argument (le nom du fichier)comme un argument. Sans cela, un tel argument pourrait être traité comme une chaîne d'option.
N'utilisez simplement pas xargs
pour ça. Utiliser un for
boucle :
for i in $(seq 1 15); do
mv ${i}_* $i
done
Encore mieux est d'utiliser l'expansion des accolades au lieu de seq
:
mkdir {1..15}
for i in {1..15}; do
mv ${i}_* $i
done