Pesquisa recursiva e substituição em arquivos de texto no Mac e Linux


127

No shell linux, o comando a seguir procurará e substituirá recursivamente todas as instâncias de 'this' por 'that' (não tenho um shell Linux na minha frente, mas deve).

find . -name "*.txt" -print | xargs sed -i 's/this/that/g'

Como será um comando semelhante no OSX?


Provavelmente deve ser movido para, apple.stackexchange.compois não é genérico o suficiente para linux nem todos os desenvolvedores.
— AlikElzin-kilaka

Respostas:


246

O OS X usa uma combinação de ferramentas BSD e GNU, portanto, é melhor sempre verificar a documentação (apesar de eu ter uma que lessnem estava em conformidade com a página de manual do OS X):

https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html

sed usa o argumento depois -icomo extensão para backups. Forneça uma string vazia ( -i '') para nenhum backup.

O seguinte deve fazer:

LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +

A -type fé apenas uma boa prática; O sed reclamará se você fornecer um diretório ou algo assim. -execé preferido sobre xargs; você não precisa se preocupar com -print0nada. O {} +no final significa que findanexará todos os resultados como argumentos a uma instância do comando chamado, em vez de executá-lo novamente para cada resultado. (Uma exceção é quando o número máximo de argumentos de linha de comando permitidos pelo sistema operacional é violado; nesse caso, findserá executado mais de uma instância.)


2
Meu "this" nesta substituição contém uma barra (localhost / site) - estou substituindo partes de uma URL em um arquivo .html .... como faço para fazer essa substituição. Tentei colocar aspas duplas, mas falha.
— Timothy T.

6
Sintaxe sed permite usar quase qualquer personagem no lugar da barra, por exemplo, você poderia usar o %caráter: sed "s%localhost/site%blah/blah%". Outra alternativa é a barra invertida escapar do separador: sed "s/localhost\/site/blah\/blah/".
— TaylanUB

Obrigado, deixe-me tentar isso. I no entanto fez tentar usar {} para separar a barra e eu ainda tenho um erro ...
— Timothy T.

16
Mais alguém está recebendo illegal byte sequenceerro? se assim for, tente LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +:, funcionou para mim.
— ColdTuna

10
Isto vai substituir apenas uma ocurreny por arquivo, uso /gde múltiplas ocurrencies comoLC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
— jamesjara

152

Para o mac, uma abordagem mais semelhante seria a seguinte:

find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"

10
Eu gostaria de poder votar isso toda vez que voltar a usá-lo. Seria às +15 agora, fácil.
— Droogans

Por alguma razão, isso não funciona para mim. Não faz nada. Eu estou dentro do form360 pasta e estou tentando mudar todas as instâncias de string com o nome EASYFORM para form360, estou executando o seguinte comando:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
— Andres Ramos

2
para mim, essa deve ser a resposta correta. É o único que funcionou para mim.
— nosequeldeebee

1
-print0 | xargs -0 não funciona no meu mac quando o nome do arquivo contém espaço.
— user2807219

1
. sed:: Edição no local só funciona para arquivos regulares
— codeslapper

14

Como solução alternativa, estou usando esta no Mac OSX 10.7.5

grep -ilr 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @

O crédito vai para: resposta de Todd Cesere


Este funciona bem! Outros scripts adicionam um fim de linha extra em alguns casos no OSX! Muito obrigado!
— Sebastien Filion

14

No Mac OSX 10.11.5, isso funciona bem:

grep -rli 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @

xargs -I @ sed -i '' s / old-word / new-word / g '@ funcionou para mim depois de tentar tantas outras sugestões que não funcionavam. Obrigado!
— DrB

13

Nenhuma das opções acima funciona no OSX.

Faça o seguinte:

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt

1
como escapar '/' se SEARCH_FOR e REPLACE_WITH forem caminhos?
— rraallvv

Use um delimitador diferente. Se você estiver usando caminhos, dois pontos ou cano funcionariam. 's | SEARCH | REPLACE | g', por exemplo. Nosso uso de chaves, como em {SEARCH} {REPLACE} '.
— Dannysauer 6/09/13

1
pergunta, tentando não no Mac - mas parece gerar um erro? Por exemplo, meu caminho é interpretado como um arquivo? -bash: localhost / NoHost: Nenhum tal lima ou diretório
— Timothy T.

isso não ocorre através de pastas profundas. Apenas um nível.
— Sergey Romanov

Para obter mais informações sobre este comando, leia este link lifehacker.com/5810026/…
— kuzdu

7

Uma versão que funciona no Linux e no Mac OS X (adicionando a -eopção a sed):

export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'

Eu tive que fazer a exportação a partir desta resposta + a linha da resposta aceita (eu não queria que os arquivos de backup a ser gerado)
— Lance

2
para corrigir o erro 'sequência ilegal de bytes', tente configurar o LOCALE antes de executar o comando: export LC_CTYPE=C && export LANG=C
— cjoy

NUNCA EXECUTE isso com '*' em vez de '* .filetype' como eu fiz se estiver usando o Git. Ou você pode dizer adeus a todo o seu trabalho não publicado.
— Sergey

1
A versão para Mac do comando sed requer uma '' após o -i, assim que esta resposta está incorreta
— G Huxley

2

Sempre que digito esse comando, sempre pareço manejá-lo ou esquecer uma bandeira. Criei um Gist no github baseado na resposta do TaylanUB que substitui uma descoberta global do diretório atual. Isso é específico do Mac OSX.

https://gist.github.com/nateflink/9056302

É legal porque agora eu apenas abro um terminal e copio:

curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

Você pode obter alguns erros estranhos na sequência de bytes, então aqui está o código completo:

#!/bin/bash
#By Nate Flink

#Invoke on the terminal like this
#curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Usage: ./$0 [find string] [replace string]"
  exit 1
fi

FIND=$1
REPLACE=$2

#needed for byte sequence error in ascii to utf conversion on OSX
export LC_CTYPE=C;
export LANG=C;

#sed -i "" is needed by the osx version of sed (instead of sed -i)
find . -type f -exec sed -i "" "s|${FIND}|${REPLACE}|g" {} +
exit 0

2

Este é o meu viável. no mac OS X 10.10.4

grep -e 'this' -rl . | xargs sed -i '' 's/this/that/g'

Os itens acima usam find alterarão os arquivos que não contêm o texto de pesquisa (adicione uma nova linha no final do arquivo), que é detalhada.


2

Se você estiver usando um terminal zsh, poderá usar magia curinga:

sed -i "" "s/search/high-replace/g" *.txt


1

Usei esse formato - mas ... descobri que precisava executá-lo três ou mais vezes para que ele realmente alterasse todas as instâncias que eu achava extremamente estranhas. A execução uma vez alteraria algumas em cada arquivo, mas não todas. Executar exatamente a mesma string duas a quatro vezes capturaria todas as instâncias.

find . -type f -name '*.txt' -exec sed -i '' s/thistext/newtext/ {} +

Você precisava executar esse comando várias vezes gporque o seu regex sed precisa de um no final, caso contrário, ele substitui apenas a primeira ocorrência de thistextuma linha. Portanto, o seu regex deve sers/thistext/newtext/g
— Les Nightingill

0

https://bitbucket.org/masonicboom/serp é um utilitário go (ou seja, multiplataforma), testado no OSX, que pesquisa e substitui recursivamente o texto em arquivos em um determinado diretório e confirma cada substituição. É novo, então pode ser de buggy.

O uso se parece com:

$ ls test
a  d  d2 z
$ cat test/z
hi
$ ./serp --root test --search hi --replace bye --pattern "*"                         
test/z: replace hi with bye? (y/[n]) y
$ cat test/z
bye

0
find . -type f | xargs sed -i '' 's/string1/string2/g'

Consulte aqui para mais informações.


-3

O comando no OSX deve ser exatamente o mesmo que é o Unix sob a bonita interface do usuário.


Eu pensei isso, mas não. Ele coloca um ./ na frente dos arquivos ao alimentar o sed, portanto o sed reclama 'código de comando inválido'. Talvez eu só estou cansado ;-)
— Jack

@ JacobusR, recorte e cole no seu terminal OSX - você deve inserir algo um pouco diferente.
— Glenn Jackman

3
Você pode querer -print0adicionar aos findsinalizadores e -0aos xargssinalizadores.
— jmtd

Você também pode simplesmente usar em -exec sed -i s/this/that/g {} \+vez de -printe xargs
— Marian

@ JacobusR - isso funciona, mesmo se houver um nome de caminho './' principal. No entanto, se houver um espaço no nome do arquivo, diga "./jacobus \ R.txt", o uso de xargspoderá ver o "./jacobus" delimitado por espaço como um arquivo para o qual passar e sed, em seguida, com "R.txt" , nenhum dos quais existe.
— Brett Hale

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.