42 votes

Copier la liste des fichiers

J'ai une liste de fichiers séparés par des espaces dans un fichier list.txt. J'aimerais les copier dans un nouveau dossier.

J'ai essayé de faire :

cp 'cat list.txt' nouveau_dossier

mais cela n'a pas fonctionné.

Comment feriez-vous cela ?

Mise à jour :

Merci pour toutes vos réponses très intéressantes. Je n'ai pas demandé autant :)

Après avoir essayé la solution ci-dessus une deuxième fois, il semble que cp ait affiché l'aide d'utilisation car le dossier nouveau_dossier n'existait pas encore ! Désolé, cela semble être une erreur stupide... Quand je crée le dossier avant, ça fonctionne.

Cependant, j'ai beaucoup appris de toutes vos réponses et solutions, merci pour le temps que vous prenez pour les écrire.

76voto

Damian Powell Points 315

Pas besoin de cat du tout:

xargs -a list.txt cp -t new_folder

Ou en utilisant des options longues:

xargs --arg-file=list.txt cp --target-directory=new_folder

Voici quelques versions de shell. Notez que certaines variables ne sont pas mises entre guillemets ou que des boucles for sont utilisées spécifiquement car l'OP a spécifié que les noms de fichiers sont séparés par des espaces. Certaines de ces techniques ne fonctionneront pas pour des entrées avec un nom de fichier par ligne dans lesquelles les noms de fichiers contiennent des espaces.

Bash:

for file in $(

``ou

cp $(

`sh (ou Bash):

# toujours pas de cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt

ou

# aucun ici non plus
while read -r line; do cp $line new_folder; done < list.txt

ou

# miaou
for file in $(cat list.txt); do cp "$file" new_folder; done

ou

# miaou
cp $(cat list.txt) new_folder` ``

41voto

Keith Sirmons Points 2558

Essayez d'utiliser xargs :

cat list.txt | xargs -J % cp % new_folder

Mise à jour :

J'ai fait cela sur OS X qui a une version différente des versions GNU/Linux. Le xargs qui provient de GNU findutils n'a pas de -J mais il a -I qui est similaire (comme Dennis Williamson l'a souligné dans un commentaire). La version OS X de xargs a à la fois -I et -J qui ont des comportements légèrement différents - l'un ou l'autre fonctionnera pour cette question d'origine.

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder

9voto

Naseer Points 1223

J'avais une réponse embarrassante et compliquée ici plus tôt, mais la réponse de Denis m'a rappelé que j'avais manqué l'essentiel. Alors, j'ai supprimé ma réponse initiale. Mais comme personne n'a dit cette chose très basique, je pense que ça vaut la peine de le mettre ici.

La question originale est "J'ai un fichier texte avec une liste de noms de fichiers séparés par des espaces. Comment puis-je les copier dans un répertoire cible." Au début, cela peut sembler difficile ou compliqué, car vous pensez devoir extraire les éléments du fichier d'une manière spécifique. Cependant, lorsque le shell traite une ligne de commande, la première chose qu'il fait est de séparer la liste d'arguments en jetons et (voici la partie que personne n'a dite clairement) les espaces séparent les jetons. (Les sauts de ligne séparent également les jetons, raison pour laquelle le test de Doug Harris avec une liste séparée par des sauts de ligne a donné le même résultat.) C'est-à-dire que le shell attend et peut déjà gérer une liste séparée par des espaces.

Donc, tout ce que vous avez à faire ici est de mettre la liste séparée par des espaces (que vous avez déjà) à l'endroit approprié dans votre commande. Votre commande est une variation de ceci :

cp fichier1 fichier2 fichier3...fichier# cible

La seule complication est que vous voulez obtenir la liste des fichiers de 1 à # à partir de votre fichier texte.

Comme Dennis le souligne dans son commentaire, votre tentative initiale (cpcat liste.txtnouveau_dossier) aurait dû fonctionner déjà. Pourquoi ? Parce que la commande interne cat liste.txt est traitée en premier par le shell et se transforme en fichier1 fichier2 fichier3...fichier#, ce que le shell attend et veut à cet endroit de la commande. Si cela n'a pas fonctionné alors soit (1) vous avez fait une faute de frappe soit (2) vos noms de fichiers étaient d'une manière ou d'une autre étranges (ils contenaient des espaces ou d'autres caractères inhabituels).

La raison pour laquelle toutes les réponses de Dennis fonctionnent simplement est qu'elles fournissent la liste de fichiers nécessaire pour que cp fonctionne, plaçant cette liste là où elle doit être dans toute la commande. Encore une fois, la commande elle-même a cette structure :

cp liste-de-fichiers répertoire_cible

Il est facile de voir comment tout cela se met en place dans cette version :

cp $(


[`$()`](http://mywiki.wooledge.org/CommandSubstitution) fait que le shell exécute la commande à l'intérieur des parenthèses et substitue ensuite sa sortie à cet endroit dans la ligne plus grande. Ensuite, le shell exécute la ligne dans son ensemble. En passant, `$()` est une version plus moderne de ce que vous faisiez déjà avec les backticks (`). Ensuite : `<` est un opérateur de redirection de fichier. Il dit au shell de déverser le contenu de `liste.txt` dans l'entrée standard. Comme la partie `$()` est traitée en premier, voici ce qui se passe par étapes :

1.  ``cp $( `# scinder la ligne en trois jetons : cp, $(` ``
``` ``*   `cp fichier1 fichier2 fichier3...fichier# nouveau_dossier` `# substituer le résultat de $(`
`` ```

```` ``` ``

Évidemment, l'étape 2 est simplement la commande `cp` normale que vous vouliez.

Je réalise que je répète beaucoup (peut-être trop) cette explication, mais je pense que ça vaut la peine de le faire. Comprendre _exactement_ comment le shell traite une commande peut vous aider à l'écrire mieux et à la simplifier beaucoup. Cela vous montrera également où les problèmes sont susceptibles de se cacher. Dans ce cas, par exemple, ma première question aurait dû être sur des noms de fichiers drôles ou une possible faute de frappe. Aucune acrobatie n'était nécessaire.

`` ``` ```` `````

0voto

Alex Points 131

En plus de la réponse de @dennis-williamson:

Si vous avez un fichier avec des commentaires et que vous voulez utiliser xargs, excluez les lignes commençant par # en utilisant grep:

TARGET_PATH="/chemin/complet/"
grep -e '^[^#]' filelist.txt | xargs \
    cp --parents \
    --target-directory "$TARGET_PATH"

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X