
Quero encontrar arquivos recursivamente em minha árvore de origem por conteúdo. Eu tentei o seguinte usando grep:
$ grep -rn printf | grep %s | grep bcm_errmsg\(rv\)
Isso me retorna todas as linhas que eu queria, mas agora gostaria de obter o nome de cada arquivo correspondente, então mudei para:
$ grep -rn printf | grep %s | grep -l bcm_errmsg\(rv\)
mas em vez de imprimir os nomes dos arquivos, só recebo
(standard input)
impresso em stdout. Como faço para corrigir isso para obter cada nome de arquivo e caminho (para usar sed
nele)?
O que eu quero fazer: Encontre todos os arquivos com printf
linhas que também contenham %s
e bcm_errmsg(rv)
aplique o seguinte comando sed aos arquivos encontrados:
sed -i 's/%s/%d/g; s/bcm_errmsg(rv)/rv/g;'
Responder1
Acho que você está complicando demais as coisas. Para procurar string foo
em todos os arquivos localizados no diretório e subdiretórios atuais, simplesmente execute
grep -r "foo" *
Por padrão, grep gera a linha correspondente anexada pelo nome do arquivo onde foi encontrado.
Em vez disso, o seguinte exibirá apenas o nome do arquivo, sem a linha correspondente:
grep -rl "foo" *
Responder2
Seguindo a ideia inicial do @steeldriver, você pode fazer:
egrep -rl '.*printf.*%s.*bcm_errmsg\(rv\).*' . | xargs -d '\n' sed -i '/printf/ s/%s/%d/; /printf/ s/bcm_errmsg(rv)/rv/'
Responder3
grep -rlZP '(?=.*printf)(?=.*%s)(?=.*bcm_errstr\(rv\))' . |
xargs -r0 sed -i -e '
/%s/!b
/printf/!b
/bcm_errstr(rv)/!b
s/%s/%d/g;s/bcm_errstr(rv)/rv/g
'
Primeiro executamos um diretório recursivo. do diretório atual que procura arquivos que possuem as strings: printf, %s e bcm_errstr(rv) na mesma linha, mas talvez em qualquer ordem. As grep
opções que nos ajudam a fazer isso são:
-r
=> será iniciado recursivamente em todos os arquivos no diretório atual e abaixo.-l
=> listará os nomes de arquivos que correspondem aos critérios, ou seja, todas as 3 strings na mesma linha.-Z
=> os nomes de arquivos selecionados são separados por nulos (\0) em vez da nova linha usual (\n) para que possamos lidar com qualquer tipo de nome de arquivo.-P
=> habilitar o mecanismo regex Perl, por meio do qual podemos usar lookaheads para determinar se as 3 strings existem na mesma linha.
Do outro lado do pipe, xargs
está aguardando o recebimento dos nomes dos arquivos, separados por \0. Em seguida, ele alimenta todos esses nomes de arquivos, tanto quanto possível, para a linha de comando sed. O comando sed você já conhece da sua pergunta anterior, onde ele realiza as subs. somente nas linhas que contêm as 3 cordas na mesma linha.