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>
3 Réponses :
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
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
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.
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.
OOOOOH J'ai des tirets dans les noms. Ceci explique cela. Je n'ai même pas pensé à eux. Je ne les utiliserai plus.
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>
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)