Salvando linhas de saída individuais em variáveis

2

Estou usando find -mtime -2 para encontrar arquivos modificados nas últimas 24 horas ou menos. A saída é assim.

/home/user/logs/file-2014-08-22.log
/home/user/logs/file-2014-08-23.log

Eu preciso salvar a primeira linha da saída em uma variável e depois salvar a segunda linha em uma variável separada. Eu não posso simplesmente canalizá-lo. Eu sei que você pode sugerir | grep 22 ou 23 , mas isso é parte de um script bash que será executado muitas vezes, haverá um conjunto diferente de arquivos com nomes diferentes na próxima vez, então grep seria muito específico. Poderia awk realizar isso? Se sim, como? .

    
por chubby_monky 25.08.2014 / 06:43

3 respostas

6

Supondo que não há espaços ou similares em nenhum dos seus nomes de arquivos, existem algumas maneiras de fazer isso. Uma é apenas usar uma matriz:

files=( $(find -mtime -2) )
a=${files[1]}
b=${files[2]}

files será uma matriz de todos os caminhos gerados por find em ordem, indexados de zero. Você pode obter as linhas que quiser com isso. Aqui salvei a segunda e a terceira linhas em a e b , mas você também pode usar os elementos da matriz diretamente.

Uma alternativa se você tiver o GNU find ou outro com a opção printf é usá-lo em combinação com read e substituição de processos :

read junk a b junk < <(find -printf '%p ')

Este transforma toda a saída de find em uma única linha e fornece essa linha como entrada para read , o que salva a primeira palavra (caminho) em junk, o segundo em a , o terceiro em b e o restante da linha em junk novamente.

Da mesma forma, você pode introduzir o paste command para o mesmo efeito em qualquer POSIX sistema compatível:

read junk a b junk < <(find -mtime -2 | paste -s)

paste -s converterá sua entrada em uma única linha separada por tabulação, com a qual read poderá lidar novamente.

No caso geral, se você estiver satisfeito em executar o comando principal mais de uma vez (não é necessário aqui), você pode usar sed facilmente:

find | sed -n 2p

Isso imprimirá apenas a segunda linha da saída, suprimindo a saída comum com -n e selecionando a linha 2 para p rint. Você também pode unir head e tail para o mesmo efeito, o que provavelmente será mais eficiente em um arquivo muito longo.

Todos os itens acima têm o mesmo efeito de armazenar as segundas e terceiras linhas em a e b , e todos ainda têm a suposição de que não há espaços, tabulações, novas linhas ou quaisquer outros caracteres que aconteçam esteja em seu valor do separador de campo de entrada ( IFS ) em qualquer um dos nomes de arquivo.

Note que a ordem de saída de find é indefinida, então "segundo arquivo "não é realmente um identificador útil, a menos que você esteja organizando para que seja solicitado de outra maneira. É provável que seja algo próximo da ordem de criação em muitos casos, mas não em todos.

    
por 25.08.2014 / 06:59
4

Com bash 4.x , você pode usar o arquivo de mapas :

$ mapfile -t <<< "$(find -mtime -2)"
$ printf "%s\n" "${MAPFILE[0]}"
/home/user/logs/file-2014-08-22.log
$ printf "%s\n" "${MAPFILE[1]}"
/home/user/logs/file-2014-08-23.log

mapfile lê as linhas da entrada padrão na variável de matriz indexada, a matriz padrão é MAPFILE . Você pode especificar o nome da matriz:

mapfile -t array <<< "$(find -mtime -2)"

-t option causa mapfile remove uma nova linha à direita de cada linha lida.

    
por 25.08.2014 / 07:12
1

Sem restringir-se a um número conhecido de arquivos encontrados ou entradas repetidas no código ou na linha de comando, você pode usar a seguinte linha (embora longa) para atribuir nomes de variáveis sequenciais a cada saída de find

A linha / script:

$ counter=0; for log_file in $(find -mtime -2); do echo $log_file; if [ -f $log_file ]; then ((counter++)); eval var_$counter='readlink -f $log_file'; fi; done

Saída (como em find normal), se a linha echo não for removida:

.
./logs
./logs/file-2014-08-22.log
./logs/file-2014-08-23.log

Mas, aqui, faço a triagem de arquivos válidos usando a opção if -f .... (conforme descrito aqui ) e, portanto, a informação desejada é preservada:

$ echo $counter
2
$ echo $var_1
/home/shadowe/Videos/logs/file-2014-08-22.log
$ echo $var_2
/home/shadowe/Videos/logs/file-2014-08-23.log

Assim, as variáveis seqüenciais contêm o caminho absoluto dos resultados find e podem ser facilmente incorporadas a um script existente.

Espero que isso ajude.

    
por 25.08.2014 / 08:12