J'essaie de trouver des fichiers dans le terminal pour le moment. J'ai trouvé de nombreuses réponses sur la façon de trouver des fichiers correspondant à un modèle spécifique, tels que des fichiers se terminant par une certaine extension, ou à partir d'une certaine période, etc.
Cependant, ce que j’ai essayé de comprendre, c’est comment trouver et copier plusieurs fichiers arbitraires, comme une liste de fichiers spécifiques.
Disons, par exemple, que j'ai les dossiers et fichiers suivants
/Documents/Folder_1/
avec contenu:
file1.txt file2.txt file3.txt file4.txt
/Documents/Folder_2/
avec contenu:
file5.txt file6.txt file7.txt
/Documents/Folder_3/
avec contenu:
file8.txt, file9.txt
et ce que je veux faire est de créer un nouveau dossier appelé Folder_4
et de copier file2.txt
, file5.txt
et file9.txt
dans ce nouveau dossier.
Est-il possible de le faire via un terminal?
Ce que j'ai essayé de faire est de faire une liste de texte des noms de fichiers et de l'appeler quelque chose comme: list.txt, par exemple.
file2.txt
file5.txt
file9.txt
et charger ce fichier texte dans la commande Rechercher, par exemple comme ceci:
find /home/usr/Documents -name $cat list.txt
en pensant que j'alimenterais ensuite la sortie avec une liste de textes ou une commande de copie, mais cela ne semble pas fonctionner.
Je me demande s’il existe un moyen de rechercher plusieurs fichiers arbitraires au moyen de la commande Rechercher, ou si j’y pense de la mauvaise façon?
EDIT: Je voulais juste dire merci pour les réponses et résumer la façon dont j'ai fini par aborder ce problème. J'apprécie tout particulièrement que quelqu'un m'ait expliqué que la commande find ne soit pas conçue pour accepter plus d'une entrée sans le drapeau -o, cela m'a fait me sentir un peu moins stupide de ne pas pouvoir le comprendre!
Ce que j'ai fini par faire était de créer un petit script Shell et de demander une entrée utilisateur et d'utiliser un tableau et une boucle for pour parcourir la liste.
En gros, le script avec lequel je me suis retrouvé ressemble plus ou moins à ceci:
#!/bin/bash
#take user input
echo "Please enter list of filenames to search"
read list
echo "Please enter the folder path to search"
read path
echo "Please enter the destination folder path"
read destination
#use inputted list as input for array, and then use a for loop to find each item on list one by one
array=($list)
for i in "${array[@]}"
do
find "$path" -iname "i" -exec cp '{}' "$destination" \;
done
Malheureusement, le prédicat -name
de la commande find
n'accepte qu'un seul motif. Si vous souhaitez rechercher plusieurs fichiers par nom, vous devez les chaîner avec l'opérateur -o
(logique OR
) - quelque chose comme:
find Documents/ \( -name "file2.txt" -o -name "file5.txt" -o -name "file9.txt" \) -print
Cela rend difficile la construction de la recherche par programme à partir d’une liste; le plus proche, je peux venir à votre tentative de commande est:
lire la liste dans un tableau Shell
mapfile -t files < list.txt
utiliser le printf
du shell bash pour construire la liste de prédicats
printf -- '-name "%s" -o ' "${files[@]}"
utiliser eval
pour évaluer la chaîne de commande résultante
Il y a une ride ici dans la mesure où si nous utilisons la fonctionnalité de réutilisation du format de printf
pour construire la liste de cette façon, nous nous retrouvons avec un 'balançant' -o
; nous pouvons contourner ce problème en terminant la liste par un test -false
(puisque -o -false
est un booléen non-op), de sorte que notre chaîne de prédicat finale devienne
"\( $(printf -- '-name "%s" -o ' "${files[@]}") -false \)"
Mettre tout cela ensemble - étant donné
$ tree dir
dir
├── Folder_1
│ ├── file1.txt
│ ├── file2.txt
│ ├── file3.txt
│ └── file4.txt
├── Folder_2
│ ├── file5.txt
│ ├── file6.txt
│ └── file7.txt
└── Folder_3
├── file8.txt
└── file9.txt
3 directories, 9 files
et
$ cat list.txt
file2.txt
file5.txt
file9.txt
ensuite
$ mapfile -t files < list.txt
$ eval find dir/ "\( $(printf -- '-name "%s" -o ' "${files[@]}") -false \)" -print
dir/Folder_1/file2.txt
dir/Folder_2/file5.txt
dir/Folder_3/file9.txt
Pour copier des fichiers au lieu de simplement les lister, vous pouvez alors faire
$ mkdir newdir
$ eval find dir/ "\( $(printf -- '-name "%s" -o ' "${files[@]}") -false \)" -exec cp -t newdir/ -- {} +
résultant en
$ tree newdir
newdir
├── file2.txt
├── file5.txt
└── file9.txt
0 directories, 3 files
Remarque: la commande eval
est puissante et potentiellement susceptible d’abus: utilisez-la avec précaution.
En pratique, étant donné que vous semblez vouloir ne trouver qu'un petit nombre de fichiers, l'approche KISS consiste à accepter le hit de performance de plusieurs appels find
et à n'utiliser qu'une boucle. :
while read -r f; do
find dir/ -name "$f" -exec cp -v -- {} newdir/ \;
done < list.txt
ou même en utilisant xargs
xargs -a list.txt -n1 -I@ find dir/ -name @ -exec cp -v -- {} newdir/ \;
J'essaie toujours de comprendre votre question de la manière la plus claire.
Essayez-vous de trouver des fichiers spécifiques dans un répertoire? Si oui et qu'il existe un modèle que vous pouvez utiliser avec des expressions régulières pour les trouver, utilisez find <directory> -regex "your_regex"
et s'il n'y en a pas, vous devez spécifier le nom du fichier que vous recherchez. Vous pouvez utiliser le python script ci-dessous pour copier vos fichiers.
import shutil
import os
list = [file1.txt, file2.txt] # replace with your file list.
destination = "your_destination" # replace with your destination.
directory = os.getcwd() # replace os.getcwd() with your directory.
for dirpath, dirname, filenames in os.walk(directory, topdown='true'):
for file in filenames :
if file in list :
shutil.copy(os.path.join(dirpath, file), destination)
Si ce qui précède n'est pas votre cas, je suggère d'utiliser ceci:
find <somewhere> -name "something" | xargs cp -t <your_destination>
Le script bash ci-dessous, s'il est exécuté à partir du répertoire de niveau supérieur (par exemple, à partir de votre dossier ~/Documents
), créera un nouveau répertoire et copiera/déplacera les fichiers souhaités. Par défaut, seuls les fichiers trouvés sont répercutés, ce qui permet à l'utilisateur de vérifier s'il s'agit du résultat souhaité. Remarque: remplacez echo
par cp
pour copier ou mv
pour le déplacer.
La liste des fichiers est assignée à la variable regex
avec le séparateur \|
(ce qui pour grep
signifie logique ou instruction)
copy_files.sh
:
#!/bin/bash
new_dir="./dir4"
[ -d "$new_dir" ] || mkdir "$new_dir"
regex="file1\|file3\|file6"
find . -print0 | while IFS= read -d $'\0' line;
do
if grep -q "$regex" <<< $line
then
filename=$(basename "$line")
printf "%s\n" "Found $filename"
echo "$line" "$new_dir"/"$filename"
# Replace echo with cp for copying,
# or mv for moving
fi
done
bash-4.3$ ./copy_files.sh
Found file6
./dir3/file6 ./dir4/file6
Found file3
./dir1/file3 ./dir4/file3
Found file1
./dir1/file1 ./dir4/file1
Comme vous pouvez le voir ci-dessus, le script indique quel fichier a été trouvé et où il le copierait ou se déplacerait. Par exemple, à la dernière ligne, il copierait/déplacerait ./dir1/file1
vers ./dir4/file1
s'il utilisait réellement cp
ou mv
et pas seulement echo