grep canalizando para sed, substituindo inline; mas eu quero sed para imprimir o nome do arquivo e alterei a linha. É possível?

6

Aqui está o meu comando (pausa intencional):

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

No nível alto: grep para FOO no diretório blah ; canalizar apenas o nome do arquivo (por causa de -l ) para sed ; sed executa uma substituição inline ( -i '' ) e imprime somente o termo alterado para /dev/stdout .

Se eu omitir o -l e o pipe, recebo isso de volta de grep :

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

O que eu quero é sed para executar a substituição inline e, em seguida, mostre-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 . Eu tenho que fazer um segundo grep após o sed ?

    
por GJTorikian 25.02.2012 / 21:17

3 respostas

3

Uma possibilidade seria passar a saída de grep para um filtro sed 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ê pode fazer com que sed imprima o número da linha (com o comando = ) quando encontrar uma correspondência e fazer mais 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
    
por 27.02.2012 / 01:43
1

Como eu não sou falante nativo de inglês, eu provavelmente não entendi.

Para "grep" um diretório você precisa de '-r'. O uso de '-l' imprime apenas o nome do arquivo e pára o grepping 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
    
por 25.02.2012 / 22:30
1

Acho que você está complicando o problema tentando fazer isso de uma só vez. Você simplesmente pode fazer um

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

para obter a lista de arquivos com números de linha e substituições (isso deve funcionar, contanto que seus nomes de arquivos não contenham dois pontos, mas isso é uma má idéia no Mac OS mesmo assim ...). Depois 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 você tiver muitos arquivos). Se você está preocupado com as duplicações, pode colocar as duas linhas em um script ou função e fazer substituições de variáveis lá.

    
por 29.08.2013 / 02:00

Tags