Contexte
Sous Linux, vous pouvez:
- Liste un groupe de fichiers avec
ls Filename*
- Supprimer un groupe de fichiers avec
rm Filename*
- Déplacer un groupe de fichiers avec
mv Filename* /New/Directory
- Mais vous ne pouvez pas copier un groupe de fichiers avec:
cp Filename* *.bak
Modifier la cp
commande Linux pour copier un groupe de fichiers
J'ai un groupe de fichiers que je voudrais copier sans entrer les noms un par un et en utilisant la cp
commande:
$ ls gmail-meta3*
gmail-meta3 gmail-meta3-REC-1558392194-26467821
gmail-meta3-LAB-1558392194-26467821 gmail-meta3-YAD-1558392194-26467821
Comment puis-je utiliser quelque chose comme l'ancienne commande DOS copy gmail-meta3* *.bak
?
Je ne veux pas taper quatre fois une commande similaire:
cp gmail-meta3-LAB-1558392194-26467821 gmail-meta3-LAB-1558392194-26467821.bak
Je cherche un script / une fonction / une application qui accepte des paramètres pour l'ancien et le nouveau groupe de noms de fichiers et non quelque chose avec des noms de fichiers codés en dur. Par exemple, un utilisateur peut taper:
copy gmail-meta3* *.bak
ou ils pourraient taper:
copy gmail-meta3* save-*
command-line
cp
ms-dos
WinEunuuchs2Unix
la source
la source
touch aa ab ba; mkdir bb; cp a* b*; ls *
*
pour les noms de fichiers source mais pas pour les noms de fichiers cibles. En tant que tel, le caractère générique de remplacement (je pense que cela a##
été suggéré mais je me penche vers%
) devra être utilisé pour la cible. Je pense que c'est ce que vous renforcez? Je ne m'attendais pas du tout à changer lacp
commande. Créez simplement un script wrapper appelécopy
qui émule (dans des limites raisonnables) la commande de copie DOS.Réponses:
Voici un exemple d'utilisation atypique de
sed
, applicable à cette tâche:De cette façon, en fait,
sed
ne changera pas les fichiers, car nous n'avons fourni aucune commande''
, mais en raison de l'option,-i[suffix]
il créera une copie de sauvegarde de chaque fichier. J'ai trouvé cette approche lorsque je cherchais. Existe-t-il un moyen de créer une copie de sauvegarde d'un fichier sans taper deux fois son nom?la source
$ time sed -i.bak '' gmail-meta3*
=real 0m0.069s
real 0m0.037s
. Si les fichiers supprimés et exécuter une seconde fois près de lacp
vitesse:real 0m0.051s
.sed
est plus rapide lorsque les fichiers cibles existent déjà, maiscp
est plus lent lorsque les fichiers cibles existent. En fait, je vide les caches et les tampons plutôt quesync
lors de grands tests de synchronisation, mais je n'ai rien fait cette fois-ci. Comme cela peut s'égarer dans un tout autre feuilleton hors sujet, je regrette de partager mes résultats de test :( Est-il trop tard pour prétendre que cette conversation n'a jamais eu lieu? Ce n'est pas non plus un disque dur, c'est un SSD Samsung Pro 960 NVMe sur 4 canauxfree
commande. Les écritures réelles sur l'appareil ont lieu à un moment choisi par un algorithme qui prend en compte l'âge du cache et la pression de la mémoire sur la machine. Si vous essayez plusieurs tests, les premières lectures de fichiers seront supprimées du disque, mais les lectures suivantes proviendront très probablement directement de la mémoire (voirsync; echo 3 > /proc/sys/vm/drop_caches
).cp
commande, mais je ne peux pas dire qu'il existe une différence de performances significative .Vous pouvez utiliser
find
:Cela trouvera dans le répertoire courant
.
tous les fichiers avec un nom correspondant au modèle glob (faites attention aux guillemets simples autour du modèle pour éviter le globbing du shell). Pour chaque fichier trouvé, ilcp
s'exécutera de nom en nom.bak. Le \; à la fin, il s'assurera qu'il exécutera chaque fichier individuellement au lieu de les transmettre tous en même temps. La profondeur maximale de 1 ne fait que rechercher dans le répertoire cuurent au lieu de revenir en arrière.la source
find . -max-depth 1 -name '"$1"'' -exec cp "{}" "{}$2" \;
lorsque $ 1 est source et $ 2 est extension?Vous pouvez utiliser une
for
boucle avecbash
. Normalement, je le taperais simplement en une ligne car ce n'est pas une tâche que j'exécute souvent:Cependant, si vous en avez besoin en tant que script:
L'utilisation est similaire à
rename
. Tester:la source
$ time for f in gmail-meta3* ; do cp -a "$f" "${f}.bak" ; done
=real 0m0.046s
0.046
secondes, ce qui signifie 0 seconde pour la perception humaine. J'essayais simplement de montrer comment je testais les réponses publiées et de transmettre des informations intéressantes aux téléspectateurs qui ont regardé lased
commande ci-dessus. Ou du moins, je voulais comparersed
aveccp
...cp
est plus rapide que la solution avecsed
. C'est donc un motif de fête :)-a
est un opérateur d'essai non standard. Pourquoi ne pas utiliser-e
? (2) «Impossible de créer un répertoire temporaire.» est un message d'erreur quelque peu trompeur. (3) Pourquoi ne pas simplement utilisermktemp -d
? (4) Vous devez tester les états de sortie. Par exemple, vous devez dire! mkdir "$FOLDER" && echo "Unable to create temporary directory." && return 1
oumkdir "$FOLDER" || { echo "Unable to create temporary directory."; return 1;}
. De même pourcp
etrename
(et peut-être mêmepushd
, si vous voulez faire attention). … (Suite)$@
; dire"$@"
. (5b) Il n'est pas nécessaire d'utiliser{
et}
lorsque vous référencez des variables comme vous le faites ("${FOLDER}"
,"${PATTERN}"
et"${file}"
); fais juste"$FOLDER"
,"$PATTERN"
et"$file"
. (6) Cela suppose que les fichiers se trouvent dans le répertoire courant.cps 's/$/.bak/' d/foo
copierad/foo
àfoo.bak
dans le répertoire courant, nond/foo.bak
.Le plus proche que vous obtiendrez probablement du paradigme DOS est
mcp
(à partir dummv
package):S'il
zsh
est disponible, sonzmv
module contribué est peut-être un peu plus proche:J'éviterais
ls
malgré tout - une variante de votre propre réponse qui est sans danger pour les espaces blancs (y compris les nouvelles lignes) seraitou peut-être
la source
mmv
c'est le package, mais dans les commentaires, vous dites que la commande l'est,mcp
mais dans la commande que vous utilisez,mmv
qui est également une commande dans lemmv
package. J'aime la direction desprintf
exemples et dans un script soigné je m'assurerais que $ 1 et $ 2 ont été passés. +1 pour faire rouler la balle :)mcp
est juste un synonyme demmv -c
printf
commande que je n'ai jamais vraiment utilisée. Êtes-vous en train de dire queprintf '%s\0' "$1"*
cela fonctionnerait s'ilgmail-meta3
était passé en tant que paramètre 1?cps gmail-meta3*
puis j'écriraisprintf '%s\0
"$ @" | tandis que ... `dans la fonction. Ou utilisez simplementfor f; do cp -- "$f" "$f.bak"; done
(comme la réponse de Xiota , mais en fonction)zmv
vous, vous pouvez utiliser le mode "remplacement de caractères génériques", que je trouve un peu plus facile à maîtriser:zmv -W -C 'gmail-meta3*' '*.bak'
solution rsync uniquement
Si vous souhaitez simplement sauvegarder vos fichiers, vous pouvez les copier dans un nouveau répertoire
rsync /path/to/dir/Filename* /path/to/backupdirectory
Cela copiera les
Filename
fichiers de/path/to/dir/
à/path/to/backupdirectory
.rsync + filerename
Si vous voulez que vos fichiers de sauvegarde aient un suffixe, les choses deviennent difficiles avec
rsync
...rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak
Cela écraserait les fichiers existants ... avec les fichiers existants (
-I
) mais seulement s'ils sont (-u
) plus récents (ce qu'ils ne sont pas) et en créant une sauvegarde, avec un suffixe.Vous pouvez également le faire dans le même répertoire. Mais il vaut mieux exclure les sauvegardes existantes.
rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak --exclude '*.bak'
la source
rsycnc
donc j'ai voté positivement mais, une méthode plus simple seraitcp Filename* /path/to/backup/dir
parce que les fichiers n'auraient pas besoin d'*.bak
uniquificateur s'ils étaient dans un répertoire séparé.Celui-ci devrait faire comme demandé:
Usage:
J'ai choisi
?
car#
il faut le citer quand c'est le premier caractère du motif, sinon il est reconnu comme début d'un commentaire.Tester:
Quelques versions antérieures du script pour ajouter un suffixe:
Semblable à la réponse @ WinEunuuchs2Unix, mais je pense que plus flexible et ne pas analyser
ls
:Mettez ceci dans votre
.bashrc
.Usage:
Alternative, avec le suffixe comme dernier argument ( via et via ):
Usage:
la source
copy gmail-meta3* old-meta3*
. Dans ma réponse, je ne pouvais pas comprendre comment entrer*
dans le nom de destination comme ma question l'avait demandé ...*
interprété par le shell, donc la fonction ne le saura pas. Il vous faudrait un autre caractère ou le citer, puis le remplacer par le nom de fichier d'origine dans la fonction.#
pourrait être utilisé comme remplacement pour*
? Vous pouvez donc tapercopy filenames# save-#
. Je pense que vous voudriez que le caractère générique soit le même pour la source et la cible.J'ai écrit ce one-liner dans mon
~/.bashrc
.find
Je suppose que de bien meilleures réponses en utilisant peuvent être affichées. Des réponses encore meilleures pourraient être écrites en C. Espérons que cette Q&R lance le bal pour de meilleures réponses:for f in "$1"*; do
:$1
est legmail-meta3
paramètre etf
est la liste des fichiers correspondants. Combiné, cela signifie pour gmail-meta3, gmail-meta3-LAB-9999, etc., procédez comme suit[[ ! "$f" == *"$2" ]] &&
:$f
est le même quef
ci-dessus.$2
est le.bak
paramètre passé. Combiné, cela signifie que si le nom de fichier ne se termine pas.bak
(parce que nous ne voulons pas copier.bak
et créer.bak.bak
), procédez comme suitcp -a "$f" "$f$2";
copiez gmail-meta3 dans gmail-meta3.bak, etc.done
: boucle et récupère le nom de fichier suivant dans lagmail-meta3
liste *.cps gmail-meta3 .bak
Exemple de sortieEn utilisant la question comme exemple, voici à quoi elle ressemble en action:
Remarque: Cela utilise l'
-a
indicateur avec lacp
commande pour conserver les horodatages et vous donner une meilleure compréhension de vos sauvegardes de fichiers.Notez que les copies de fichiers ont exactement la même date et l'heure que les originaux. Si le
-a
paramètre était omis, ils recevraient la date et l'heure actuelles et ne ressembleraient pas à une véritable sauvegarde, sauf que la taille du fichier serait la même.la source
ls
find
je suppose que vous êtes conscient des dangers de l'analyse syntaxiquels
? Mais dans votre cas, aucun n'est nécessaire: faites-lefor file in "$1"*; do copy -a "$file" "$file$2"; done
- c'est complètement sûr et beaucoup plus simple que tout type d'indirection vials
oufind
et unewhile
boucle.Une autre méthode pour répondre à vos besoins consiste à copier les fichiers dans un répertoire temporaire et à utiliser la
rename
commande pour les renommer.Si vous en avez besoin en tant que script, vous pouvez l'utiliser comme ça
Et vous pouvez l'utiliser comme ceci:
Ceci est un exemple
la source