Grep mot dans un fichier puis copiez le fichier

9

J'ai une collection de fichiers (* .zip, * .txt, * .tar.gz, * .doc, ... etc). Ces fichiers résident dans un chemin. Je veux trouver tous les fichiers (* .txt), puis copier uniquement les fichiers texte contenant des mots spécifiques (par exemple LINUX / UNIX).

J'ai couru ce qui suit:

find . -name "*.txt" | grep 'LINUX/UNIX'

Cette commande a pu trouver tous les fichiers texte, puis "grep" a filtré les fichiers texte résultants en listant uniquement les fichiers texte contenant 'LINUX / UNIX'.

Comment puis-je copier ces fichiers finaux (c'est-à-dire les fichiers texte qui contiennent 'LINUX / UNIX') vers un chemin spécifique de votre choix?

J'ai essayé de postuler xargs

find . -name "*.txt" | grep 'LINUX/UNIX' | xargs cp <to a path>

Mais ça n'a pas marché


la source

Réponses:

21

Essayer:

grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0r cp -t /path/to/dest

Étant donné que cette commande utilise la séparation NUL, elle est sûre pour tous les noms de fichiers, y compris ceux avec des noms difficiles qui incluent des espaces, des tabulations ou même des retours à la ligne.

Ce qui précède nécessite GNU cp. Pour MacOS / FreeBSD, essayez:

grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0 sh -c 'cp "$@" /path/to/dest' sh

Comment ça fonctionne:

  1. grep options et arguments

    • -rindique à grep de rechercher récursivement dans la structure du répertoire. (Sur FreeBSD, -rsuivra les liens symboliques dans les répertoires. Cela n'est vrai ni pour OS / X ni pour les versions récentes de GNU grep.)

    • --include '*.txt'indique à grep de ne renvoyer que les fichiers dont les noms correspondent au glob *.txt(y compris ceux cachés comme .foo.txtou .txt).

    • -l indique à grep de ne renvoyer que les noms des fichiers correspondants, pas la correspondance elle-même.

    • --nullindique à grep d'utiliser des caractères NUL pour séparer les noms de fichiers. ( --nullEst prise en charge par grepsous GNU / Linux , MacOS et FreeBSD , mais pas OpenBSD .)

    • LINUX/UNIX indique à grep de ne rechercher que les fichiers dont le contenu inclut l'expression régulière LINUX/UNIX

    • .rechercher dans le répertoire courant. Vous pouvez l'omettre dans les versions récentes de GNU grep, mais vous devrez ensuite passer un --terminateur d'option pour cpvous prémunir contre les noms de fichiers commençant par -.

  2. xargs options et arguments

    • -0 indique à xargs d'attendre une entrée séparée par NUL.

    • -rindique à xargs de ne pas exécuter la commande sauf si au moins un fichier a été trouvé. (Cette option n'est pas nécessaire sur BSD ou OSX et n'est pas compatible avec OSX xargs.)

    • cp -t /path/to/destcopie les répertoires dans le répertoire cible. ( -tnécessite GNU cp.)

John1024
la source
Pour Mac OS X, et probablement BSD, vous voudrez utiliser --null au lieu de -Z. De plus, je pense que cp -tc'est uniquement Linux.
Edward Falk
1
@EdwardFalk Bon point. Merci. J'ai mis à jour pour utiliser --nullet ajouté une version pour BSD / OSX qui n'utilise pas cp -t.
John1024
@ StéphaneChazelas Merci pour les améliorations.
John1024
1
OpenBSD grepn'a pas --null.
Kusalananda
@Kusalananda Merci. Réponse mise à jour pour noter qu'OpenBSD ne prend pas en charge --null.
John1024
14

Plus facilement (fonctionnalités POSIX uniquement):

find . -type f -name '*.txt' -exec grep -q LINUX/UNIX {} \; -exec cp {} /path/to/dest \;
Caractère générique
la source
3

Le liner sh / Bash one suivant est une autre méthode, mais ne fonctionnera que dans le répertoire en cours, et ne récurrera pas:

for f in ./*.txt; do if grep -l 'LINUX/UNIX' "$f"; then cp "$f" /path/to/dest/; fi; done

L' -loption grep affichera une liste des fichiers qui sont copiés, bien que vous puissiez les utiliser -qsi vous ne voulez rien voir à l'écran.

Arronical
la source
0

Je ne sais pas pourquoi la chaîne d'origine n'a pas fonctionné. La commande suivante fonctionne pour moi.

trouver / -nom (nom de fichier *) | grep '(filename.extention)' | xargs cp -t ./

Dans mon cas, filename * est une collection de fichiers de même nom avec différents types de fichiers (txt, zip, etc.). Je fais grep pour trouver uniquement le nom de fichier.txt et le copier dans mon répertoire de destination (qui est actuellement, ./).

SamL
la source