como verificar se a primeira linha do arquivo contém uma string específica? [duplicado]

4

Eu preciso escrever um script de shell que encontre e imprima todos os arquivos em um diretório que comece com a string: #include . Agora, eu sei como verificar se uma string está no arquivo, usando:

for f in 'ls'; do
    if grep -q 'MyString' $f; then:
        #DO SOMETHING
    fi

mas como posso aplicar isso na primeira linha? Eu pensei em talvez criar uma variável da primeira linha e verificar se ela começa com #include , mas não tenho certeza de como fazer isso. Eu tentei o comando read , mas não consigo ler em uma variável.

Eu gostaria de ouvir outras abordagens para esse problema; talvez awk? De qualquer forma, lembre-se de que preciso verificar se a primeira linha começa com #include , não se contiver essa sequência. É por isso que eu encontrei essas perguntas: link eles não estão ajudando completamente.

    
por Z E Nir 09.11.2018 / 10:33

4 respostas

7

É fácil verificar se a primeira linha começa com #include in sed:

sed -n '1{/^#include/p};q'   file

Ou simplificado:

sed -n '/^#include/p;q'   file

Isso terá uma saída apenas se o arquivo contiver #include na primeira linha. Isso só precisa ler a primeira linha para fazer o teste, então será muito rápido.

Assim, um loop de shell para todos os arquivos (com sed) deve ser assim:

for file in *
do
    [ "$(sed -n '/^#include/p;q' "$file")" ] && printf '%s\n' "$file"
done

Se existem apenas arquivos (não diretórios) no pwd.

Se o que você precisa é imprimir todas as linhas do arquivo, uma solução semelhante ao primeiro código postado funcionará:

sed -n '1{/^#include/!q};p'   file
    
por 09.11.2018 / 10:53
5
for file in *; do
  [ -f "$file" ] || continue
  IFS= read -r line < "$file" || [ -n "$line" ] || continue
  case $line in
    ("#include"*) printf '%s\n' "$file"
  esac
done

Para imprimir o conteúdo do arquivo em vez de seu nome, substitua o comando printf por cat < "$file" .

Se o seu awk suportar a extensão nextfile e você não se importar com os possíveis efeitos colaterais de abrir arquivos não regulares:

awk '/^#include/{print substr(FILENAME, 3)}; {nextfile}' ./*

Com zsh , você pode substituir ./* por ./*(-.) para passar apenas arquivos regulares (ou links simbólicos para arquivos regulares, como para a abordagem [ -f ... ] acima) para awk .

Ou para imprimir o conteúdo do arquivo em vez do nome:

awk 'FNR == 1 {found = /^#include/}; found' ./*

(aquele é portátil).

    
por 09.11.2018 / 10:41
2
for file in *
do
  [ -f "$file" ] && head -n 1 < "$file" | grep -q '^#include' && cat < "$file"
done

Cuidado com o fato de que, com a opção -q habilitada, grep sairá com um status zero, mesmo que um erro tenha ocorrido.

    
por 09.11.2018 / 10:56
0

Esta questão é um exemplo perfeito em que as soluções bash e sed são bastante complexas, mas a tarefa pode ser muito mais simples com o awk (GNU):

gawk 'FNR==1 && /^#include/{print FILENAME}{nextfile}' *
    
por 09.11.2018 / 18:04

Tags