Como encontrar logs que contêm determinada string em muitos arquivos gz / regular e salvá-la como um / mais arquivos txt?

3

Nova pergunta em 22.9.2016, abaixo!

Meu caminho é assim:

~/Desktop/logs
├── first_folder
|   ├── 11.11 (folder)
│   |   ├── access_log
│   |   ├── access_log.1.gz
│   |   :
│   |   └── access_log.40.gz
|   └── 11.12 (folder)
│       ├── access_log
│       ├── access_log.1.gz
│       :
│       └── access_log.16.gz
├── second_folder (folder)
|   ├── 31.11 (folder)
│   |   ├── access_log
│   |   ├── access_log.1.gz
│   |   :
│   |   └── access_log.20.gz
|   └── 31.15 (folder)
│       ├── access_log
│       ├── access_log.1.gz
│       :
:       └── access_log.38.gz
└── last_folder
    ├── 91.11 (folder)
    |   ├── access_log
    |   ├── access_log.1.gz
    |   :
    |   └── access_log.25.gz
    └── 91.15 (folder)
        ├── access_log
        ├── access_log.1.gz
        :
        └── access_log.30.gz

De todos os logs, tenho que extrair os dados que contêm string: /Jan/2016

Pergunta # 1

Como posso obter todos os registros de todos os arquivos em todas as pastas e salvá-los como single_file.txt

Editar # 1

Resposta possível:

$ find . -name \*.* | xargs -0 zgrep -E '/Jan/2016' > single_file.txt

O arquivo é realmente muito grande, muito GB.

Saída:

single_file.txt
./first_folder/11.11/access_log.9.gz: ... text ...
./first_folder/11.12/access_log.9.gz: ... text ...
./second_folder/31.11/access_log.9.gz: ... text ...
./second_folder/31.11/access_log.9.gz: ... text ...
:

Pergunta # 2

Como posso obter todos os registros de todos os arquivos em todas as pastas e salvá-los individualmente, dependendo dos registros que eu pegar de first_folder, second_folder etc, como first.txt, second.txt .

A saída seria algo como:

first.txt
./first_folder/11.11/access_log.9.gz: ... text ...
./first_folder/11.12/access_log.9.gz: ... text ...
:
second.txt
./second_folder/31.11/access_log.9.gz: ... text ...
./second_folder/31.15/access_log.9.gz: ... text ...
:

Pergunta # 3

Como posso obter uma lista de todos os arquivos que contêm a string /Jan/2016 ?

Se eu usar este comando, ele recuperará todos os arquivos:

$ find ~/Desktop/logs/ -type f | xargs zgrep -l "/Jan/2016"  

Saída:

Terminal
/home/name/Desktop/logs/first_folder/11.11/access_log.9.gz
/home/name/Desktop/logs/first_folder/11.12/access_log.8.gz
/home/name/Desktop/logs/second_folder/31.11/access_log.6.gz
:

Editar # 2

@ código do waltinator e correção do @ Zanna-s:

pushd ~/Desktop/logs
for dir in * ; do
    if [[ -d "$dir" ]] ; then
        outname="$dir.txt"
        find "$dir" -type f -print0 | xargs -0 zgrep -l '/Jan/2016' >"$outname"
    fi
done
popd

me dará a estrutura:

~/Desktop/logs
├── first_folder
|   └── first.txt
├── second_folder
|   └── second.txt
:
└── last_folder
    └── last.txt

onde first.txt-last.txt conterá caminhos para arquivos específicos que contenham string / Jan / 2016.

first.txt
first_folder/11.11/access_log.9.gz
first_folder/11.11/access_log.8.gz
first_folder/11.12/access_log.9.gz
first_folder/11.12/access_log.8.gz

Pergunta # 4 (22.9.2016)

Eu precisava modificar /Jan/2016 para um determinado período de tempo ... por exemplo, 1/Nov/2014-31/Apr/2015 so em um código que o @Zana forneceu em vez do /Jan/2016 que usei /(Nov|Dec)/2014|/(Jan|Feb|Mar|Apr)/2015 . Aviso é lançado:

xargs: Warning: a NUL character occurred in the input.  It cannot be passed through in the argument list.  Did you mean to use the --null option?

Todos os resultados não são retornados nos arquivos criados, embora todos os arquivos sejam criados.

    
por vayacondios2015 13.09.2016 / 21:33

2 respostas

3
  
  1. Tenha dados que contenham string em arquivos de texto separados, dependendo de uma pasta (exemplo: primeira pasta - first.txt, etc.)
  2.   

Você pode usar um loop muito simples para criar um arquivo de texto com os registros desse diretório dentro do diretório:

for d in ~/Desktop/logs/* ; do zgrep -E '/Jan/2016' "$d"/* >"$d"/out.txt ; done

Desktop/logs
├── first_folder
│   ├── access_log
│   ├── access_log.gz
│   └── out.txt
└── second_folder
    ├── access_log
    ├── access_log.gz
    └── out.txt

Usando esse pequeno ajuste no script do Waltinator :

for d in ~/Desktop/logs/* ; do
    if [[ -d "$d" ]] ; then
        outname="$d".txt
        find "$d" -type f -print0 | xargs -0 zgrep -E '/Jan/2016' >"$outname"
    fi
done

fornecerá essa estrutura:

├── first_folder
│   ├── access_log
│   └── access_log.gz
├── first_folder.txt
├── second_folder
│   ├── access_log
│   └── access_log.gz
└── second_folder.txt

Notas

  • for d in ~/Desktop/logs/* ; do faz um loop sobre o conteúdo de ~/Desktop/logs e faz algo com eles
  • if [[ -d "$d" ]]; then faz algo apenas se $d for um diretório
  • find "$d" -type f -print0 procura dentro dos diretórios $d dos arquivos e os envia com o separador nulo para que possamos usar
  • xargs -0 constrói um comando com a saída do comando anterior como argumentos, usando o caractere nulo como separador (caso contrário, nomes de arquivos com espaços quebram essa abordagem)
  • zgrep pesquisas em arquivos compactados / compactados
por Zanna 14.09.2016 / 11:01
4

A maneira moderna de usar find , tendo em mente que você verá um nome de arquivo contendo espaços, é com -print0 e xargs -0 :

# list all filenames containing '/Jan/2016'
find ~/Desktop/logs -type f -print0 | xargs -0 zgrep -l '/Jan/2016'
# 1. Have all the data from all folders that contain that string under one text file
find ~/Desktop/logs -type f -print0 | xargs -0 zgrep -l '/Jan/2016' >one.text.file
#
# 2. Have data that contains string in a separate text files depending on a folder (example: first folder - first.txt etc)
pushd ~/Desktop/logs
for dir in * ; do
    if [[ -d "$dir" ]] ; then
        outname="$dir.txt"
        find "~/Desktop/logs/$dir" -type f -print0 | xargs -0 zgrep -l '/Jan/2016' >"$outname"
    fi
done
popd
    
por waltinator 13.09.2016 / 21:59