Como imprimir o conteúdo do arquivo apenas se a primeira linha corresponder a um determinado padrão?

11

Estou escrevendo um script, quero verificar se a primeira linha do arquivo corresponde a um determinado padrão e se o imprime. Como posso conseguir isso?

Como verifico o padrão? Existe uma maneira de verificar o padrão e com base na saída fazer alguma coisa ..

Edição: Por favor, dê uma olhada nesta pergunta: /programming/5536018/how-to-get-match-regex-pattern-using-awk-from-file

Eu quero algo assim, mas nenhum deles funcionou para mim. Basicamente, quero verificar se a primeira linha corresponde a um padrão regex ou não e, com base nisso, imprima as linhas do arquivo.

Mathew
fonte
1
Qual é o resultado esperado? Qual é o padrão que você está procurando? O que você tentou até agora?
tachomi 28/09/15
@tachomi editado por favor, dê uma olhada
Mathew

Respostas:

17

Você poderia fazer isso com ed:

ed -s infile <<\IN 2>/dev/null
1s/PATTERN/&/
,p
q
IN

o truque aqui é tentar substituir PATTERNon- 1stline consigo mesmo. edocorrerá um erro se não conseguir encontrar o padrão especificado, portanto, ,p(imprimir o arquivo inteiro) será executado apenas se 1s/PATTERN/&/for bem-sucedido.

Ou com sed:

sed -n '1{
/PATTERN/!q
}
p' infile

isso qocorre se a primeira linha não ( !) corresponder PATTERN, caso contrário, ptodas as linhas serão delimitadas.
Ou, como apontado por Toby Speight , com o GNU sed:

sed '1{/PATTERN/!Q}' infile

Qé o mesmo que qmas não imprime o espaço do padrão.

don_crissti
fonte
Você poderia, em Qvez de qusar o GNU sed, ou dantes q(portátil) para não exigir o -nsinalizador e o pcomando: sed '1{/PATTERN/!Q}' infileou sed -e '1{' -e '/PATTERN/!{' -e 'd' -e 'q' -e '}' -e '}' infile, respectivamente.
Toby Speight
dreinicia o ciclo de comando Isso sempre me chama a atenção! : - |
Toby Speight
Com o GNU, sedo primeiro sedcomando reclama sed: -e expression #1, char 10: extra characters after command(por causa do p), mas as edúltimas sedsugestões funcionam bem.
Skippy le Grand Gourou
Nota: As soluções fornecidas por esta resposta têm o mérito, além de outras respostas, de poderem ser aplicadas em um tubo.
Skippy le Grand Gourou
1
@SkippyleGrandGourou - Você tentou desligá-lo em uma frase sem separar os comandos com ponto e vírgula - esta é a maneira correta de fazê-losed -n '1{/PATTERN/!q};p'
don_crissti
15

Com o baú de ferramentas POSIX:

{ head -n 1 | grep pattern && cat; } <file
cuonglm
fonte
1
{double} <doce.
mikeserv
@mikeserv: Pretendo usá-lo para evitar que novas pessoas confundam, mas Stephane editado é mais claro.
precisa saber é o seguinte
8
 awk '/pattern/{print FILENAME}; {nextfile}' ./*.txt

imprimiria o nome dos txtarquivos não ocultos no diretório atual cuja primeira linha corresponde à expressão regular estendida patterncom as awkimplementações suportadasnextfile .

Se, em vez de imprimir o nome do arquivo, desejar imprimir todo o conteúdo do arquivo, você poderá:

 awk 'FNR == 1 && ! /pattern/ {nextfile}; {print}' ./*.txt

É eficiente, pois executa apenas um comando, mas awknão sendo o comando mais eficiente para despejar o conteúdo de um arquivo, com arquivos grandes, é possível obter melhores desempenhos fazendo algo como:

 awk '/pattern/{printf "%s\0", FILENAME}; {nextfile}' ./*.txt |
   xargs -r0 cat

Ou seja, use apenas awkpara imprimir a lista de arquivos que correspondem (delimitados por 0) e dependem catpara despejar seu conteúdo.

Stéphane Chazelas
fonte
6

Se você está escrevendo um script de shell, pode fazer algo como

for file in ./*; do head -n 1 "$file" | grep -q 'PATTERN' && cat "$file"; done

Ou, em Perl:

perl -Tlne '$f = /PATTERN/ if $. == 1; print if $f; $. = 0 if eof' ./*
terdon
fonte
@ Stéphane Chazelas: Talvez close ARGVseja mais idioma do que atribuir $..
precisa saber é o seguinte
O @terdon Yours parece um código de golfe, tudo em uma linha, sem colchetes em torno dos nomes das variáveis ​​e não está incentivando uma estrutura limpa. E você tinha um cifrão faltando quando eu postei, essa não é a maneira de ensinar o bash. Eu suponho que esses fatores provêm do background perl que você também parece ter, então você será perdoado! ;)
Olá pessoal e bem-vindo ao site! Eu converti sua resposta em um comentário, pois as respostas só devem ser postadas se elas estiverem respondendo à pergunta real. Este não é um fórum no sentido clássico e queremos apenas perguntas e respostas simples aqui. Você pode dar uma olhada no centro de ajuda ou fazer um tour para entender melhor o site. Dito isto, minha formação é realmente de biologia, portanto, sim, meu código está longe de ser limpo :) No entanto, não vejo como os colchetes ajudariam aqui, as aspas já protegem a variável. O que quebraria isso que os colchetes protegeriam?
terdon
@ Guest ah, desculpe, esqueci que você não pode comentar. Sinta-se livre para vir e explicar no bate-papo , tenho certeza que posso aprender alguma coisa.
terdon
5

Oldschool, apenas traduza sua frase em comandos padrão:

for file in *; do
    if head -n 1 "${file}" | grep -q 'PATTERN'; then
        cat "${file}"
    fi
done

Para aprender bash, é um bom começo. Se você só precisa de uma solução rápida, tente as respostas sed, awk ou perl. Ambos são legais, mas são idiomas próprios que você precisa (e provavelmente quer) para aprender.

É um exemplo bastante simples, portanto, se você quiser saber mais, também pode tentar o mesmo em ruby, php, js (por exemplo, em nodejs) ou em qualquer outro idioma que permita o acesso a arquivos. Mesmo C / C ++ ou Java deve ser fácil de gerenciar com uma pequena tarefa.

hóspede
fonte
1
É basicamente o mesmo que o meu, exceto pelo uso em if/elsevez de [ ] &&.
terdon