Comment copier et renommer des fichiers trouvés dans la fonction «trouver» Linux?


17

J'ai un dossier nommé /home/user/tempsqui contient 487 dossiers. Dans chaque dossier, j'ai un fichier appelé thumb.png.

Je veux copier tous les fichiers nommés thumb.png dans un dossier séparé et les renommer en fonction du dossier dont ils sont issus.


les renommer, comment? Si vous remplacez le délimiteur de répertoire par quelque chose - disons souligné (_), vous pouvez obtenir des collisions avec des fichiers, qui contiennent déjà un soulignement. C'est vrai pour chaque caractère valide, et à côté de / et \ 0, qui sont interdits dans les noms de fichiers, il n'y a pas de refuge - n'importe quel caractère peut produire une collision.
utilisateur inconnu

Les dossiers ont-ils des sous-dossiers, ou simplement une structure de dossiers simple et large?
utilisateur inconnu

Réponses:


8

Voici:

for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;

Éditer:

la sagesse canonique, soit dit en passant, est que l'utiliser findpour cela est une mauvaise idée - simplement utiliser l'expansion du shell est beaucoup plus fiable. En outre, cela suppose bash, mais je suppose que c'est une hypothèse sûre :)

modifier 2:

pour plus de clarté, je vais le décomposer:

# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do

    # replace 'temps' with 'new_folder' in the path
    # '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
    new_file=${file/temps/new_folder};

    # drop '/thumb' from the path
    # '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
    cp "$file" "${new_file/\/thumb/}";
done;

les détails sur la ${var/Pattern/Replacement}construction peuvent être trouvés ici .

les guillemets dans la cpligne sont importants pour gérer les espaces et les sauts de ligne, etc. dans les noms de fichiers.


new_file = new_folder? À quoi sert la barre oblique inverse devant la barre oblique new_file/\/thumb?
utilisateur inconnu

1
@user: ${VARIABLE/PATTTERN/REPLACEMENT}produit la valeur de VARIABLEmais avec le motif remplacé par le texte de remplacement. Ici, le modèle est /thumb(le /besoin doit être échappé pour qu'il ne ressemble pas ${new_file//PATTERN/REPLACEMENT}, ce qui en fait un remplacement global au lieu d'un remplacement de première occurrence) et le texte de remplacement est vide.
Gilles 'SO- arrête d'être méchant'

Bien sûr, maintenant je le vois. :)
utilisateur inconnu

1
Vous supposez que les 487 répertoires sont directement sous /home/user/temps, ce qui n'est pas clair à la question. Si ce n'est pas le cas, vous devez trouver ou **.
Gilles 'SO- arrête d'être méchant'

@Gilles - Je suis en effet, c'est ainsi que j'ai lu la question. Appréciez le point, cependant :)
Simon

5

Cela fonctionne pour des sous-répertoires arbitrairement profonds:

$ find temps/ -name "thumb.png" | while IFS= read -r NAME; do cp -v "$NAME" "separate/${NAME//\//_}"; done
`temps/thumb.png' -> `separate/temps_thumb.png'
`temps/dir3/thumb.png' -> `separate/temps_dir3_thumb.png'
`temps/dir3/dir31/thumb.png' -> `separate/temps_dir3_dir31_thumb.png'
`temps/dir3/dir32/thumb.png' -> `separate/temps_dir3_dir32_thumb.png'
`temps/dir1/thumb.png' -> `separate/temps_dir1_thumb.png'
`temps/dir2/thumb.png' -> `separate/temps_dir2_thumb.png'
`temps/dir2/dir21/thumb.png' -> `separate/temps_dir2_dir21_thumb.png'

La partie intéressante est l' expansion des paramètres ${NAME//\//_} . Il prend le contenu de NAMEet remplace chaque occurrence de /with _.

Remarque: le résultat dépend du répertoire de travail et du paramètre de chemin d'accès pour rechercher. J'ai exécuté la commande depuis le répertoire parent de temps. Remplacez cppar echopour expérimenter.


Échoue sur les fichiers qui contiennent une nouvelle ligne dans leur nom.
utilisateur inconnu

Eh bien, cela a très bien fonctionné. une chose de plus, j'ai aussi quelques fichiers zip dans certains sous-répertoires. est-il possible d'en extraire également des images. rappelez-vous 'zip not tar'
Mirage

1

Code d'assistance court:

#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}" 
#
mv "$1" ../tmp/"${1//\//_}"

appelons-le «deslash.sh» et rendons-le exécutable. Appelez-le avec:

find -type f -name thumb.png -exec ./deslash.sh {} ";"    

Il échouera en cas de collision

a/b/thumb.png # and 
a_b/thumb.png 

mais c'est inévitable.


0

Essaye ça

mkdir /home/user/thumbs
targDir=/home/user/thumbs

cd /home/user/temps

find . -type d | 
 while IFS="" read -r dir ; do
   if [[ -f "${dir}"/thumb.png ]] ; then
     echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
   fi
done

Éditer

J'ai ajouté des citations au cas où l'un de vos noms de répertoire aurait des caractères d'espace blanc intégrés.

Aussi je l' ai changé cette façon il n'imprimer les commandes à exécuter. Examinez la sortie du script pour vous assurer que tous les fichiers / noms de chemin semblent corrects. Lorsque vous êtes sûr qu'il n'y a aucun problème avec les commandes qui seront exécutées, supprimez le .echo


J'ai des fichiers png dans d'autres sous-dossiers, est-ce que cela fonctionnera
Mirage

pour mon dossier "A A", il produit: mv -i ./A A/thumb.png ../tmp/.png- tous les fichiers se terminent par ../tmp/.png (../tmp est mon répertoire cible).
utilisateur inconnu

Ajoutez des guillemets et des accolades autour de toutes les variables dans le code ci-dessus, c'est-à-dire "$ {dir}"
shellter

@ Mirror51 a écrit: "les fichiers dans certains sous-dossiers supplémentaires, cela fonctionnera-t-il". Oui, ça devrait. Saviez-vous que vous pouvez exécuter chaque étape de ce script séparément (ou, lorsqu'ils sont regroupés, chaque ensemble de canaux). Vous pouvez exécuter juste le find -type det voir la sortie. Cela obtient-il tous les répertoires que vous attendez? Si tel n'est pas le cas, veuillez ajouter une sortie pour montrer le problème. Bonne chance.
shellter

Ne fonctionnera pas. read direffectue le fractionnement de mots et prend, à partir d'un répertoire a\nba et b, deux instances, qu'aucun masquage ne peut résoudre.
utilisateur inconnu

-1

Pour copier, vous avez besoin de la commande cp et renommer pour linux revient à déplacer le fichier, vous devez donc le faire avec la commande mv . Sous Linux, vous devez toujours spécifier le chemin complet, depuis la source, si vous êtes dans un autre dossier, et jusqu'au dossier de destination, bien sûr. Je serais quelque chose comme ça, pour copie:

cp /source_path/file /destination_path/

ou pour renommer ou déplacer

mv /source_path/old_file /destination_path/new_name_file

Ce n'est qu'une petite partie de la question de l'affiche. Expliquez maintenant comment parcourir les répertoires et copier les vignettes :-)

le PO veut utiliserfind

Oui, tu as raison ... Je ne sais pas ce qui m'est arrivé ...
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.