web-dev-qa-db-fra.com

Comment copier plusieurs fichiers par caractère générique?

J'ai un dossier contenant un certain nombre de fichiers ABC. * (Il y a environ 100 fichiers de ce type). Je veux les dupliquer tous dans de nouveaux fichiers avec des noms commençant par DEF. *

Donc je veux

ABC.Page1
ABC.Page2
ABC.Topic12
...etc

copié dans

DEF.Page1
DEF.Page2
DEF.Topic12
...etc

Quelle est la manière la plus simple de le faire avec une commande batch (en BASH ou similaire)? Je pense à quelque chose impliquant sed ou awk ou xargs, mais j'ai du mal à trouver la syntaxe. Je pourrais écrire un script Python, mais je pense qu'il existe probablement une solution en ligne de commande qui n'est pas trop compliquée.

45
Octopus

Que diriez-vous de quelque chose comme ça dans bash:

for file in ABC.*; do cp "$file" "${file/ABC/DEF}";done

vous pouvez le tester en mettant echo devant la commande cp:

for file in ABC.*; do echo cp "$file" "${file/ABC/DEF}";done
44
Magnus

Pour le faire efficacement avec un grand nombre de fichiers, il vaut mieux éviter de démarrer un processus cp différent pour chacun. Une façon serait de les copier puis de les renommer en utilisant prename (rename est lié à ceci par défaut sur les distributions basées sur Debian). En utilisant ceci et Linux mktemp:

tmp=$(mktemp -d --tmpdir=.)
cp ABC.* "$tmp"
prename "s:$tmp/ABC:DEF:" "$tmp/"*
rmdir "$tmp"

Mise à jour

En fait, pax peut être une meilleure façon d'aller ici:

pax -rws '/^ABC/DEF/' ABC.* .

Malheureusement, bien que pax soit à la fois POSIX et Linux Standard Base, peu de distributions l'incluent actuellement par défaut.

8
Graeme

tar le fera pour vous très rapidement.

TESTER

J'ai d'abord créé 2 répertoires et 10 fichiers:

% mkdir test1 test2 ; cd test1
% for n in `seq 1 10` ; do touch ABC.file$n ; done
% ls

> ABC.file1   ABC.file2  ABC.file4  ABC.file6  ABC.file8
> ABC.file10  ABC.file3  ABC.file5  ABC.file7  ABC.file9

Ensuite, je les ai copiés:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC/DEF/' -xf -
% ls ../test2

> DEF.file1   DEF.file2  DEF.file4  DEF.file6  DEF.file8
> DEF.file10  DEF.file3  DEF.file5  DEF.file7  DEF.file9

TRANSFORMER

Donc GNU tar acceptera un sed --transform=EXPRESSION pour renommer un fichier. Cela peut même renommer seulement certains fichiers. Par exemple:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC\(.*[0-5]\)/DEF\1/' -xf -
% ls ../test2

> ABC.file6  ABC.file8  DEF.file1   DEF.file2  DEF.file4
> ABC.file7  ABC.file9  DEF.file10  DEF.file3  DEF.file5

Voilà donc un avantage.

COURANT

Considérez également qu'il ne s'agit que de deux processus tar - et que cela ne changera pas quel que soit le nombre de fichiers.

tar | tar

tar est aussi optimisé que vous le souhaiteriez. Cela n'aura jamais de nombre d'arguments problématiques ou de processus enfants incontrôlables. C'est juste A> B fait.

ARGUMENTS

J'utilise ici 7 arguments distincts combinés entre mes deux processus tar. Le plus important est répertorié ici en premier:

- stdout/stdin - cela informe tar qu'il diffusera son entrée ou sa sortie vers ou depuis stdin/stdout qu'il interprètera correctement selon qu'il construit ou extrait une archive.

-c create - ceci indique à tar de construire l'archive. L'argument suivant que tar attend est ...

-f file - nous spécifions que tar fonctionnera avec un objet file plutôt qu'avec un lecteur de bande ou autre. Et le fichier avec lequel il va travailler, comme indiqué ci-dessus, est stdin/stdout - en d'autres termes, notre |pipe.

./* tous $ PWD/fichiers - pas trop à expliquer ici sauf que l'argument archive vient en premier, donc - puis ./*.

... et de l'autre côté du |pipe...

-C change directory - ceci informe tar qu'il doit changer dans le répertoire que je spécifie avant d'effectuer toute autre action, donc en fait il suffit de cd ../test2 avant extraction.

--transform='s/ed/EXPR/' - comme cela a déjà été mentionné, cela a fait le renommage. Mais les documents indiquent qu'il peut prendre n'importe quelle expression sed ou //flag.

-x extract - après que tar ait changé notre répertoire cible et reçu nos instructions de changement de nom, nous lui demandons de commencer à extraire tous les fichiers dans son répertoire actuel à partir du -f - |pipe fichier d'archive. Pas de mystère.

5
mikeserv

Si cela ne vous dérange pas d'utiliser un outil moins standard, je recommande d'utiliser mmv (mouvement de masse) qui a été écrit pour ce type de tâches. En utilisant mcp (copie de masse), qui fait partie de la suite, vous pouvez simplement faire

mcp "ABC.*" "DEF.#1"

Il n'est pas vraiment facile de trouver des packages de téléchargement. Le paquet Debian actuel (qu'Arch utilise également dans AUR) pour compiler à la maison peut être trouvé ici .

4
jonny

Dans zsh, mettez les lignes suivantes dans votre .zshrc:

autoload -U zmv
alias zmv='noglob zmv'
alias zcp='zmv -C'
alias zln='zmv -L'

Ensuite, sur la ligne de commande, vous pouvez exécuter

zcp 'ABC(.*)' 'DEF$1'

ou simplement

zcp -W ABC.* DEF.*

Dans un autre shell, tant que vous avez installé zsh:

zsh -c 'autoload zmv; noglob zmv -CW ABC.* DEF.*'

Vous pouvez faire ceci:

for i in ABC.*; do cp {ABC,DEF}."${i#*.}"; done
1
Sara Fauzia