Procura palavras-chave especificadas em arquivos e copia para um novo nome de arquivo baseado na palavra-chave

5

Estou tentando criar um script .sh onde, se qualquer palavra-chave for encontrada em um arquivo, copie esse arquivo para o diretório /pathtofolder/keywords/$thefirstkeywordfound (sobrescrever o arquivo, se já existir). Qualquer ajuda seria apreciada com o código de cópia ( cp -rf filename /pathtofolder/keywords/$thefirstkeywordfound ) que está incorreto. Provavelmente também precisa de uma linha de código para excluir o caminho para o qual copia (/ pathtofolder / keywords /)

Observe que quero copiar o arquivo em um diretório chamado /pathtofolder/keywords/$keyword , criando-o, se necessário.

    
por Guest 10.03.2014 / 23:09

3 respostas

4

Existem vários problemas aqui. Primeiro, não tenho idéia do que você está tentando fazer com IFS='\n' , então vou ignorá-lo. Segundo, você parece estar copiando filename não uma variável chamada filename e, de qualquer forma, você não está configurando nada.

Se eu entendi o que você está tentando fazer corretamente, você está procurando por algo assim:

#!/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 $'
./foo.sh "/source/dir" "/target/dir"
' 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

Salve o script em algum lugar, foo.sh e execute-o, dando a ele a pasta a ser pesquisada como um argumento:

#!/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 $'
./foo.sh "/source/dir" "/target/dir"
' 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
    
por 11.03.2014 / 00:16
0

Você pode fazer isso com um comando awk um tanto complexo:

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}'

Eu adicionei um -o ao seu grep para que ele imprimisse apenas as partes correspondentes da linha e, em seguida, usasse awk para criar os comandos cp .

O motivo pelo qual eu não usei -m 1 em grep em vez de if (last_line!=$1) {...}; last_line=$1 foi porque, se houver várias correspondências na mesma linha, elas serão impressas como linhas separadas:

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}'
    
por 11.03.2014 / 00:19
0

Eu acho que você precisa de mais do que um simples pipeline para fazer isso. Então, eu proponho algo assim:

#!/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

Isso tira proveito de sinalizadores estendidos ( -E ) GNU grep , -w e -o . Sem essas duas bandeiras, você teria que colocar algo como um pequeno programa Perl que pode quebrar "palavras" fora das linhas de texto, selecionar uma palavra que coincida com as palavras-chave e usar isso como o nome do arquivo.

    
por 11.03.2014 / 00:24

Tags