1
votes

Copie de fichiers à partir d'une série de répertoires à partir d'une liste dans un fichier texte

J'essaie d'utiliser rsync ou cp dans une boucle for pour copier des fichiers correspondant à une liste de 200 noms stockés sur un nouveau lignes dans un fichier .txt qui correspondent aux noms de fichiers avec l'extension .pdbqt qui sont dans une série de sous-répertoires avec un dossier parent. Le fichier .txt se présente comme suit:

tr: when not truncating set1, string2 must be non-empty
cp: cannot stat '/home/ubuntu/Project/files/pdbqt/*/.pdbqt': No such file or directory

J'ai essayé d'utiliser rsync avec la commande suivante:

#!/bin/bash
for i in "$(cat /home/ubuntu/Project/working/output.txt | tr '\n' '')"; do
    cp /home/ubuntu/Project/files/pdbqt/*/"$i".pdbqt /home/ubuntu/Project/files/top/;
done

Lorsque j'exécute la commande rsync, je reçois:

rsync error: syntax or usage error (code 1) at options.c(2346) [client=3.1.2]

J'ai écrit un script bash comme suit pour tenter de le faire fonctionner:

rsync -a /home/ubuntu/Project/files/pdbqt/*/*.pdbqt \
--files-from=/home/ubuntu/Project/working/output.txt \
/home/ubuntu/Project/files/top/

Je comprends que cat n'est pas une bonne commande à utiliser, mais je n'ai pas pu trouver une solution alternative, car je suis encore nouveau dans l'utilisation de bash. En cours d'exécution, j'obtiens l'erreur suivante:

file01
file02
file08
file75
file45
...

Je suppose que l'erreur cp est générée à la suite de l'erreur tr mais je ne suis pas sûr comment se débarrasser autrement du \ n qui est lu dans la liste séparée par une nouvelle ligne.

Les résultats attendus sont ceux des sous-répertoires dans / pdbqt / code> avec les 12000 fichiers .pdbqt , les 200 fichiers de la liste output.txt seraient copiés de ces sous-répertoires dans le répertoire / top / .

p>


0 commentaires

3 Réponses :


0
votes

Les boucles

for sont bonnes lorsque vos données sont déjà dans des variables shell. Lors de la lecture des données d'un fichier, les boucles while ... read fonctionnent mieux. Dans votre cas, essayez:

while IFS= read -r file
do
    cp -i -- /home/ubuntu/Project/files/pdbqt/*/"$file".pdbqt /home/ubuntu/Project/files/top/
done </home/ubuntu/Project/working/output.txt

ou, si vous trouvez la version multiligne plus lisible:

while IFS= read -r file; do  cp -i -- /home/ubuntu/Project/files/pdbqt/*/"$file".pdbqt  /home/ubuntu/Project/files/top/; done </home/ubuntu/Project/working/output.txt

Comment ça marche

  • while IFS = lecture -r fichier; faire

    Ceci démarre une boucle while lisant une ligne à la fois. IFS = dit à bash de ne pas tronquer l'espace blanc de la ligne et -r dit à read de ne pas couper les contre-obliques. La ligne est stockée dans la variable shell appelée file.

  • cp -i - /home/ubuntu/Project/files/pdbqt/*/"$file".pdbqt / home / ubuntu / Project / files / top / p>

    Ceci copie le fichier. -i dit à cp de demander avant d'écraser un fichier existant.

  • terminé /ubuntu/Project/working/output.txt

    Ceci marque la fin de la boucle while et indique au shell d'obtenir l'entrée pour la boucle depuis /home/ubuntu/Project/working/output.txt


2 commentaires

Merci pour l'explication approfondie. J'avais vu quelques exemples mais je ne pensais pas que cela allait fonctionner dans mon cas.


De rien. Le problème avec l'approche en boucle for est qu'il est difficile de contrôler les différentes extensions (principalement partage de mots et extension de chemin ) que le shell applique à lui. L'approche while ... read évite tout cela.



0
votes

Les répertoires dans Project / files / pdbqt / * ou les fichiers * .pdbqt ont-ils des tirets ( - ) dans le nom?

L'erreur affiche la ligne dans le code source rsync options.c "Vos options ont été rejetées par le serveur. \ n"

ce qui me fait penser qu'il interprète les inodes (fichiers / dirs) dans votre glob comme des options rsync.

for i in $( < /home/ubuntu/Project/working/output.txt LC_CTYPE=C tr '\n' ' ' )
do
  cp /home/ubuntu/Project/files/pdbqt/*/"${i}.pdbqt" /home/ubuntu/Project/files/top/
done

Je pense qu'il manque un espace à votre chat.

cat /home/ubuntu/Project/working/output.txt | tr '\ n' ''

John1024 l'utilisation de tandis que et read sont meilleurs que les miens.


1 commentaires

OOOOOH J'ai des tirets dans les noms. Ceci explique cela. Je n'ai même pas pensé à eux. Je ne les utiliserai plus.



0
votes

Vous pensez correctement pour penser rsync . rsync fournit l'option --files-from = "yourfile" qui rsync tous les fichiers de votre fichier texte (par rapport au répertoire de base que vous spécifiez ensuite) à la destination (soit host: / dest / path soit localement avec / dest / path seul)

Vous voudrez pour spécifier --no-R pour dire à rsync de ne pas utiliser de noms de fichiers relatifs puisque --files-from = prend le chemin de base comme le prochain argument. Par exemple, pour transférer tous les fichiers de votre fichier texte vers un hôte distant où l'emplacement des fichiers spécifiés se trouve dans le répertoire courant, vous pouvez utiliser:

rsync -uai --no-R --files-from="textfile" ./ host:/dest/path

Où la commande spécifie essentiellement que vous lisez les noms à transférer depuis textfile où les fichiers se trouveront sous ./ (le répertoire courant) et vous transférerez les fichiers vers hôte: / dest / path sur l ' hôte que vous spécifiez. Vous pouvez consulter man 1 rsync pour plus de détails. p>


2 commentaires

Merci pour le commentaire perspicace, cela a rendu le fonctionnement de rsync un peu plus clair. Cependant, en essayant de le faire de cette façon, il n'a recherché que dans le répertoire courant et non dans les sous-répertoires de l'arborescence actuelle?


Non, il recherche dans le répertoire de base quels que soient les noms de fichiers dans votre fichier texte. Supposons que votre fichier texte ait "project / 1 / study.txt \ nproject / 2 / data.txt \ n ..." , alors si votre répertoire de base est ./ il recherche ./project/1/study.txt , ou si votre répertoire de base était / home / you / , il chercherait / home / vous / projet / 1 / study.txt . (c'est la raison pour laquelle --no-R est nécessaire, donc rsync ne tente pas d'ajouter des noms relatifs à votre répertoire de base)