Passando arquivos regulares apenas para 'sed -i'

2

Estou usando o GNU sed 4.2.2 e depois da pesquisa não consigo descobrir o motivo sed se comporta de maneira estranha em algumas situações:

Eu tenho um diretório com o seguinte:

foofile.txt
barfile.txt
bazfile.txt
config/

Caso 1

sed -i 's/foo/bar/g' *.txt

Isso funciona como eu esperava. Ele substitui todos os "foo" s por "bar" s nos três arquivos regulares.

Caso 2

sed -i 's/foo/bar/g' *
sed: couldn't edit config: not a regular file

Substitui "foo" por "bar" em barfile.txt e bazfile.txt , mas não em foofile.txt . Eu suponho que ele passa pela lista de arquivos expandidos do * em ordem alfabética e quando ele atinge config/ erros e saídas. Existe uma maneira de ter sed ignorando erros e continuar processando arquivos?

Caso 3

for file in $(find . -maxdepth 1 -type f); do sed -i 's/foo/bar/g' <"$file"; done
sed: no input files
sed: no input files
sed: no input files

Alguém poderia explicar por que sed faz isso? Por que diz que não há arquivo de entrada quando é dado um?

Eu sei que posso usar o seguinte, mas estou perguntando por que o sed age dessa maneira, e não como resolvo esse caso de uso.

find . -maxdepth 1 -type f -exec sed -i 's/foo/bar/g' {} \;
    
por Linoob 06.04.2017 / 22:20

2 respostas

3

É um comportamento normal. Em ambos os casos, sed sai com error code 4 ... por info sed :

4
     An I/O error, or a serious processing error during runtime,
     GNU 'sed' aborted immediately.

e em ambos os casos, as mensagens são auto-explicativas. Não sei ao certo o que não está claro, mas para o registro: na primeira vez que ele errar porque não pode editar um diretório e na segunda vez que ele reclama porque não pode editar stdin no local, ele precisa de um arquivo (isto é, remover esse redirecionamento antes de $file )
A maneira correta de fazer isso com find é, como você observou, via -exec ...
Com globs, você terá que usar um loop e testar se a entrada for um arquivo regular antes de executar sed . Ou, se você for um usuário zsh , basta fazer:

sed -i 's/foo/bar/g' *(.)
    
por 06.04.2017 / 23:03
2
  • Caso 2:

    Evite esse diretório com find :

    sed -i 's/foo/bar/g' 'find . -maxdepth 1 -type f'
    
  • Caso 3:

    O problema é o <"$file" no loop, que transforma o arquivo em um fluxo, então sed nunca vê um nome de arquivo. Apenas remova esse < :

    for file in $(find . -maxdepth 1 -type f); do sed -i 's/foo/bar/g' "$file"; done
    
por 07.04.2017 / 05:54