eu tenho 5.000 arquivos em uma pasta. esses arquivos são nomeados XX0000001 a XX0005000
estou tentando obter palavras de cada um desses arquivos e grep-las e a próxima linha em outro arquivo (target.txt)
tenho cerca de 30.000 palavras em alguns dos arquivos XX*
Existe alguma maneira de fazer isso ?
eu tentei :
start_number=0000001
end_number=0005000
words_file=target.txt
output_folder="output_results"
mkdir -p "$output_folder"
for ((i=start_number; i <=end_number; i++)); do
filename="XX$(printf "%07d" "$i")"
output_file="$output_folder/output_${filename}.txt"
while read -r word; do
awk -v word="$word" '{for (i=1; i<=NF; i++) if($1 ~ word) {print; next}}' "$filename" >> "$output_file"
done < "$words_file"
done
existe uma maneira mais rápida de fazer isso? meu arquivo de destino tem milhões de linhas para pesquisar; o arquivo de destino preciso tem 20 Gigabytes e 106441678 linhas
por exemplo: o arquivo XX0000001 se parece com:
Big1 Big5 Big7 Big10 Big11 (e muito mais palavras para isso; alguns arquivos XX podem até ter até 30 mil palavras)
O arquivo Target.txt se parece com:
#Grande1
Este_é_um_arquivo_contendo_xxxx
#Grande2
Este_é_um_arquivo_contendo_xxxx
#Grande3
Este_é_um_arquivo_contendo_xxxx
#Big4
Este_é_um_arquivo_contendo_xxxx
#Big5
Este_é_um_arquivo_contendo_xxxx
#Big6
Este_é_um_arquivo_contendo_xxxx
#Big7
Este_é_um_arquivo_contendo_xxxx
#Big8
Este_é_um_arquivo_contendo_xxxx
#Grande9
Este_é_um_arquivo_contendo_xxxx
#Grande10
Este_é_um_arquivo_contendo_xxxx
#Big11
Este_é_um_arquivo_contendo_xxxx
#Big12
Este_é_um_arquivo_contendo_xxxx
Você está procurando muitos termos de pesquisa em um arquivo muito grande; é improvável que encontre uma solução "rápida" em ferramentas shell/padrão. Dito isto, penso que a sua abordagem é particularmente ineficiente.
Algo assim, talvez (não testado):
Mas também não consigo imaginar que isso seja rápido, francamente.
Isso poderia ser potencialmente multithread, o que pode melhorar o rendimento.
Aqui está uma alternativa multithread. Você precisará ajustar o
threads
valor para algo apropriado ao seu ambiente operacional.Qualquer benefício disso dependerá de fatores de hardware, como memória disponível, número de núcleos de CPU e velocidade de armazenamento, bem como outras atividades no servidor.
Para fazer um loop em um conjunto de arquivos, use shell globs, por exemplo,
for f in XX0*
aqui. Se você precisar fazer um loop em um conjunto de números, tome cuidado com os zeros à esquerda, como no Bash, eles marcam o número como octal. Por exemplo, tentando seu loop, mas apenas imprimindo os números e olhando o último:Vemos que a saída é
2560
, não5000
. Porém, esse não é o caso do zsh e você não mencionou qual shell está executando, mas mesmo assim vale a pena apontar o problema.Aqui,
Não tenho certeza do que isso está fazendo, mas observarei apenas que, no script AWK, você faz um loop em todos os campos da linha de entrada, mas apenas se refere ao campo 1 (
$1
) dentro do loop.Agora, presumo que seus arquivos estejam assim:
ou seja, que existem vários padrões distintos (por exemplo,
Big1
eBig7
) em uma única linha nosXX0*
arquivos (e não, por exemplo, um por linha). Além disso, suponho que você queira encontrar linhastarget.txt
que correspondam a qualquer um dos padrões e depois imprimi-las junto com a próxima linha.Agora, o grep padrão pode imprimir "mais uma linha" após uma correspondência e pode procurar vários padrões ao mesmo tempo. A
-f
opção leva o nome de um arquivo cujas linhas formam os padrões, então você terá que pré-processar seusXX0*
arquivos para fazer com que cada padrão apareça como uma única linha. Você pode fazer isso alterando todos os espaços para novas linhas comtr
. É mais fácil usar a substituição de processo para ter a saídatr
disponívelgrep
como um arquivo, mas você também pode usar um arquivo temporário (ou talvez até canalizar a saída detr
togrep -f -
)por exemplo:
Claro, o padrão
Big1
também aparece na linha#Big10
, então é correspondido. (Mas você pode tentar a-w
opção grep para solicitar uma correspondência de palavra completa.) Se quiser remover os--
separadores, você pode canalizar o resultado porgrep -ve --
.A eficiência disso pode depender da sua implementação do grep, mas sendo uma ferramenta feita para esse propósito, provavelmente tem mais chances de ser otimizada do que fazer o mesmo em um script de shell. Os scripts de shell são lentos. Se todos os padrões estiverem no formato
Big*
, uma jogada inteligente seria procurar a parte comum apenas uma vez. Talvez a lista de padrões possa ser alterada para um único,Big(1|5|7|10)
na esperança de que funcione melhor para o mecanismo regex.