Recherchez les mots-keys spécifiés dans les files et copyz-les dans un nouveau nom de file en fonction du mot key

J'essaie de créer un script .sh où si un mot-key est trouvé dans un file, copyz ce file dans le directory /pathtofolder/keywords/$thefirstkeywordfound (écrasez le file s'il existe déjà). Toute aide serait appréciée avec le code de copy ( cp -rf filename /pathtofolder/keywords/$thefirstkeywordfound ) qui est incorrect. Il a probablement aussi besoin d'une ligne de code pour exclure le path qu'il copy (/ pathtofolder / keywords /)

Notez que je veux copyr le file dans un directory appelé /pathtofolder/keywords/$keyword , en le créant si nécessaire.

Il y a plusieurs problèmes ici. Tout d'abord, je n'ai aucune idée de ce que vous essayez de faire avec IFS='\n' donc je vais simplement l'ignorer. Deuxièmement, vous semblez copyr le filename non une variable appelée filename et dans tous les cas, vous ne le définissez pas.

Si je comprends ce que vous essayez de faire correctement, vous cherchez quelque chose comme ceci:

 #!/usr/bin/env bash ## Pass the directory to search in as an argument, ## easier to use and avoids including /pathfolder/ ## as long as your run the script from a different ## directory. dir="$1"; ## Destination directory dest="$2" ## Don't use capitalized variables in bash, ## environmental vars are CAPS and that could cause ## problems if you use something like $USER. keywords=("Florida" "FL" "Miami-Dade" "Aventura" "Bal Harbour" "Bay Harbor Islands") ## Find all files of the right size and pass their names ## to the while loop. Skip any files matching $dest find "$dir" -size +1c -path "$dest" -prune -o -type f -print0 | ## This is to make sure it works with file names containing strange ## characters like newlines. If they don't, you can remove the -print0 ## from find and simplify to `while read file name` while IFS= read -r -d $'\0' filename do for keyword in "${keywords[@]}"; do ## -m 1: stop at first match grep -qm 1 -Fw "$keyword" "$filename" && ## Create a dir for the keyword if it does not exist mkdir -p "$dest"/"$keyword" && ## copy the file if grep found a match (that's what && above means) cp -vf "$filename" "$dest"/"$keyword"/ && ## move to the next filename if the copy succeds break done done 

Sauvegardez le script quelque part, foo.sh et exécutez-le en lui donnant le dossier à searchr en tant qu'argument:

 ./foo.sh "/source/dir" "/target/dir" 

Vous pouvez le faire avec une command awk quelque peu complexe:

 timp@helez:~/tmp/cp_find_test$ ls command.sh command.sh~ test.1 test.2 test.3 timp@helez:~/tmp/cp_find_test$ cat test.1 Aventura Whatever Florida timp@helez:~/tmp/cp_find_test$ cat test.2 Random stuff Floridaasdklfj timp@helez:~/tmp/cp_find_test$ cat test.3 FL timp@helez:~/tmp/cp_find_test$ ./command.sh cp -rf ./test.3 /pathtofolder/keywords/FL cp -rf ./command.sh /pathtofolder/keywords/Florida cp -rf ./test.1 /pathtofolder/keywords/Aventura cp -rf ./command.sh~ /pathtofolder/keywords/Florida timp@helez:~/tmp/cp_find_test$ cat command.sh KEYWORDS=("Florida" "FL" "Miami-Dade" "Aventura" "Bal Harbour" "Bay Harbor Islands") IFS=$'\n' find . -size +1c -type f ! -exec grep -oHwF "${KEYWORDS[*]}" {} \; | awk 'BEGIN {FS=":"; last_line=""} {if (last_line!=$1) {print "cp -rf", $1, "/pathtofolder/keywords/"$2}; last_line=$1}' 

J'ai ajouté un -o à votre grep pour qu'il n'imprime que les parties correspondantes de la ligne, puis awk utilisé awk pour build les commands cp .

La raison pour laquelle je n'ai pas utilisé -m 1 dans grep au lieu de if (last_line!=$1) {...}; last_line=$1 if (last_line!=$1) {...}; last_line=$1 était parce que s'il y avait plusieurs correspondances sur la même ligne, elles seraient imprimées toutes en lignes séparées:

 timp@helez:~/tmp/cp_find_test$ ./command.sh cp -rf ./test.3 /pathtofolder/keywords/FL cp -rf ./command.sh /pathtofolder/keywords/Florida cp -rf ./command.sh /pathtofolder/keywords/FL cp -rf ./command.sh /pathtofolder/keywords/Miami-Dade cp -rf ./command.sh /pathtofolder/keywords/Aventura cp -rf ./command.sh /pathtofolder/keywords/Bal Harbour cp -rf ./command.sh /pathtofolder/keywords/Bay Harbor Islands cp -rf ./test.1 /pathtofolder/keywords/Aventura cp -rf ./command.sh~ /pathtofolder/keywords/Florida cp -rf ./command.sh~ /pathtofolder/keywords/FL cp -rf ./command.sh~ /pathtofolder/keywords/Miami-Dade cp -rf ./command.sh~ /pathtofolder/keywords/Aventura cp -rf ./command.sh~ /pathtofolder/keywords/Bal Harbour cp -rf ./command.sh~ /pathtofolder/keywords/Bay Harbor Islands timp@helez:~/tmp/cp_find_test$ cat command.sh KEYWORDS=("Florida" "FL" "Miami-Dade" "Aventura" "Bal Harbour" "Bay Harbor Islands") IFS=$'\n' #find . -size +1c -type f ! -exec grep -oHwF "${KEYWORDS[*]}" {} \; | awk 'BEGIN {FS=":"; last_line=""} {if (last_line!=$1) {print "cp -rf", $1, "/pathtofolder/keywords/"$2}; last_line=$1}' find . -size +1c -type f ! -exec grep -m 1 -oHwF "${KEYWORDS[*]}" {} \; | awk 'BEGIN {FS=":"} {print "cp -rf", $1, "/pathtofolder/keywords/"$2}' 

Je pense que vous avez besoin de plus qu'un simple pipeline pour le faire. Donc, je propose quelque chose comme ça:

 #!/bin/bash KEYWORD_PATTERN='Florida|FL|Miami-Dade|Aventura|Bal Harbour|Bay Harbor Islands' find . -type f | while read FNAME do if grep -Ew -q "$KEYWORD_PATTERN" $FNAME then KEYWORD=$(grep -Ew -o "$KEYWORD_PATTERN" $FNAME | head -1) echo mv $FNAME /pathtofolder/keywords/$KEYWORD fi done 

Cela tire parti des drapeaux étendus ( -E ) GNU grep , -w et -o . Sans ces deux drapeaux, vous devriez mettre quelque chose comme un petit programme Perl qui peut briser les "mots" des lignes de text, sélectionner un mot qui correspond aux mots-keys et l'utiliser comme nom de file.