Aqui está meu comando (interromper intencionalmente):

grep FOO "/Users/gjtorikian/blah" -l | xargs sed -i "" "/FOO/{s/FOO/BAR/g; w /dev/stdout }" 

No pico -level: grep para FOO no diretório blah; canalize apenas o nome do arquivo (por causa de -l) para sed; sed executa uma substituição em linha (-i "") e imprime apenas o termo alterado para /dev/stdout.

Se eu omitisse o -l e pipe, eu recebo de grep:

/Users/gjtorikian/blah/baz.cs:1:FOO /Users/gjtorikian/blah/bar.js:1:FOO 

O que eu quero é sed para realizar a substituição embutida e, em seguida, mostrar-me o arquivo e o termo substituído; por exemplo:

/Users/gjtorikian/blah/baz.cs:1:BAR /Users/gjtorikian/blah/bar.js:1:BAR 

Isso é possível? Se for importante, prefiro mantê-lo apenas com grep / sed. Preciso fazer um segundo grep após o ?

Comentários

  • Não ' não vejo uma maneira de obtenha o nome do arquivo atual em sed, então você provavelmente precisará de um segundo grep.
  • Além disso, você não ' não precisa do '', que ' é o padrão.
  • No OS X, '' não é o padrão .

Resposta

Uma possibilidade seria passar a saída de grep para um sed filtro separado.

 grep -l FOO "/Users/gjtorikian/blah/"* | { tee /dev/fd/3 | xargs sed -i -e "/FOO/{" -e "s/FOO/BAR/g" -e "w /dev/stdout" } 3>&1 | sed "s/:FOO$/:BAR/"  

Você poderia fazer sed imprimir o número da linha (com o comando =) quando ele encontrar uma correspondência e prosseguir pós-processamento.

Provavelmente seria mais claro usar o awk.

 for x in "/Users/gjtorikian/blah/"*; do awk " sub(/FOO/, "BAR") {found=1; print FILENAME ":" NR ":" "BAR" >"/dev/stderr"} 1 {print} END {exit(!found)} " "$x" >"$x.tmp" && mv "$x.tmp" "$x" done  

Resposta

Como eu “mn ou falante nativo de inglês, provavelmente não entendi.

Para “grep” um diretório você precisa de “-r”. O uso de “-l” imprime apenas o nome do arquivo e interrompe o grep após a primeira ocorrência.

# pattern=/home ; grep -l "$pattern" /etc/[a-z]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home 

Resposta

Acho que você está complicando demais o problema tentando resolvê-lo de uma vez. Você simplesmente pode fazer um

grep -H -n /Users/gjtorikian/blah | sed "s/\(^.*?:[0-9]+?:\).*FOO.*/\1BAZ/" 

para obtenha a lista de arquivos com números de linha e substituições (isso deve funcionar, desde que seus nomes de arquivo não contenham dois pontos, mas é uma má ideia no Mac OS de qualquer maneira …). Depois disso, você pode emitir um

sed -i "" "s/FOO/BAR/g" /Users/gjtorikian/blah 

Nenhum grep e xarg é necessário aqui (você pode fazer um “find … | xarg” se tiver muitos arquivos, no entanto). Se você estiver preocupado sobre as duplicações, você pode colocar as duas linhas em um script ou função e fazer substituições de variáveis.

Comentários

  • sed -i ... muda os tempos de arquivos mesmo se o fluxo não for alterado.
  • @jww: você ' está certo, que ' s porque é um editor de fluxo, não um editor de arquivos, então a opção -i viola a filosofia do Unix ( mywiki.wooledge .org / BashFAQ / 021 # Using_nonstandard_tools ). Se você quiser evitar isso, use ex (por exemplo, ex -sc '%s/FOO/BAR/ge|x' /Users/gjtorikian/blah).

Resposta

Substitua recursivamente FOO por BAR no diretório atual (modo silencioso)

grep -rl "FOO" | xargs sed -i "s/FOO/BAR/" 

Resposta

Uma linha

grep -n FOO * -R|awk -F\: "{ print $1 }"|sort|uniq|while read file; do sed -i "s/FOO/BAR/g" $file; done 

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *