comando sed com a opção -i falhando no Mac, mas funciona no Linux


303

Usei com sucesso o seguinte sedcomando para pesquisar / substituir texto no Linux:

sed -i 's/old_link/new_link/g' *

No entanto, quando tento no meu Mac OS X, recebo:

"comando c espera \ seguido de texto"

Eu pensei que meu Mac roda um shell BASH normal. E aí?

EDITAR:

De acordo com o @High Performance, isso se deve ao fato de o Mac sedter um sabor diferente (BSD), portanto, minha pergunta seria como replicar esse comando no BSD sed?

EDITAR:

Aqui está um exemplo real que causa isso:

sed -i 's/hello/gbye/g' *

1
Isso significa que sedvê um "c" nos seus dados como um comando. Você está usando uma variável? Poste algo que represente mais de perto o comando real e alguns dados que você está processando. Você pode obter uma demonstração simples desse erro fazendo isso echo x | sed c.
Pausado até novo aviso.

@ Dennis, o comando simples acima causas isso, embora os dados que de processamento é um site inteiro (estou convertendo todos os links de imagem), incluindo arquivos HTML e CSS ...
Yarin

Respostas:


397

Se você usar a -iopção, precisará fornecer uma extensão para seus backups.

Se você tem:

File1.txt
File2.cfg

O comando (note a falta de espaço entre -ie ''e -efazê-lo funcionar em novas versões do Mac e no GNU):

sed -i'.original' -e 's/old_link/new_link/g' *

Crie 2 arquivos de backup como:

File1.txt.original
File2.cfg.original

Não há uma maneira portátil de evitar a criação de arquivos de backup, porque é impossível encontrar uma mistura de comandos sed que funcione em todos os casos:

  • sed -i -e ...- não funciona no OS X, pois cria -ebackups
  • sed -i'' -e ... - não funciona no OS X 10.6, mas funciona no 10.9 ou superior
  • sed -i '' -e ... - não está trabalhando no GNU

Nota Como não há um comando sed funcionando em todas as plataformas, você pode tentar usar outro comando para obter o mesmo resultado.

Por exemplo, perl -i -pe's/old_link/new_link/g' *


4
Eu tive o mesmo problema. Obrigado por esta solução. Mas onde eu tentei com 'man sed' encontrar a descrição de '-i', nada sobre o uso de -i '' para ignorar backups existe. Esta é a minha primeira culpa. Segundo, quando o erro "comando espera \ seguido de texto" aparece, por que não nos diz diretamente que espera um nome de backup para a opção '-i' !! ?? Tal coisa acontece em toda parte: você recebe um erro, mas não o motivo, e então procura o manual que não explica nada sobre ele. Então você pesquisa no google para encontrar alguém que também tenha o mesmo problema. Quero dizer, por que não dar exemplo no manual?
Lukmac 19/08/12

ou diga-nos por que o erro existe, em vez de apenas uma mensagem sem informação de que ocorre um erro. Esta é uma sugestão para todos os fabricantes de ferramentas, se eles puderem ler este comentário.
Lukmac

5
@lukmac Tanto quanto se sedsabe, você forneceu um sufixo de backup. O sufixo de backup é s/old_link/new_link/g. O próximo argumento depois disso deve ser os comandos de edição. Por interpretar os comandos como o nome do backup, o nome do arquivo foi o primeiro a ser utilizado como comando de edição, mas eles não eram válidos.
Barmar

2
Isso sempre será um problema? Existe alguma maneira de a Apple conseguir criar uma solução alternativa / pacote GNU sed com OSX? Ou, o GNU sed não suporta sed -i '' -e ...?
BLONG

5
sed -i'' -eparece não funcionar como esperado no mac 10.14
MoOx

64

Acredito no OS X quando você usa -i, uma extensão para os arquivos de backup é necessária . Experimentar:

sed -i .bak 's/hello/gbye/g' *

Usando o GNU, seda extensão é opcional .


55

Isso funciona com as versões GNU e BSD do sed:

sed -i'' -e 's/old_link/new_link/g' *

ou com backup:

sed -i'.bak' -e 's/old_link/new_link/g' *

Observe a falta de espaço após a -iopção! (Necessário para GNU sed)


7
O primeiro não funciona em OSX (Eu apenas testei em 10.6.8)
Marcin

4
Para mim, no OS X (10.10.3), o primeiro criou arquivos de backup com o sufixo -e. Nada de bom. A segunda foi a única coisa que funcionou para mim consistentemente entre o Ubuntu e o OS X. Porém, como eu não queria arquivos de backup, tive que executar um rmcomando logo depois para excluí-lo.
Brendan

1
Primeira linha deve ser reescrita com um espaço para trabalhar em 10.10: sed -i'' ...=>sed -i '' ...
Daniel Jomphe

3
@DanielJomphe Mas adicionar esse espaço não funciona no GNU sed
Brice

1
O @marcin first funciona para mim também no OSX 10.11.2. A única coisa é que ele cria um arquivo de backup, que precisa ser removido posteriormente. O segundo parece melhor, pois não precisamos descobrir o nome do arquivo mais tarde.
vikas027

41

Teve o mesmo problema no Mac e resolveu-o com brew:

brew install gnu-sed

e use como

gsed SED_COMMAND

você pode definir o sedalias como gsed(se quiser):

alias sed=gsed

3
Por que você deu exatamente a mesma resposta que Ohad Kravchick ?
gniourf_gniourf

1
definição do alias como este não é uma grande idéia
SantaXL

1
Em vez de um alias, conforme recomendado na página de distribuição correspondente, adicione-o ao caminho: PATH = "$ (brew - prefix) / opt / gnu-sed / libexec / gnubin: $ PATH"
y.luis

24

Ou você pode instalar a versão GNU do sed no seu Mac, chamada gsed, e usá-la usando a sintaxe padrão do Linux.

Para isso, instale gsedusando ports (se você não o tiver, obtenha-o em http://www.macports.org/ ) executando sudo port install gsed. Então, você pode executarsed -i 's/old_link/new_link/g' *


24
.. ou se você usa homebrew, então instalagnu-sed
Sudar

1
Obrigado @Sudar, gostei duas vezes!
Andrew Swan

9

Seu Mac realmente executa um shell BASH, mas isso é mais uma questão de qual implementação do sed você está lidando. Em um Mac, o sed vem do BSD e é sutilmente diferente do sed que você pode encontrar em uma caixa típica do Linux. Eu sugiro você man sed.


3
Obrigado por apontar a questão do BSD - mas eu sou bastante analfabeta e só preciso de uma solução rápida para o meu comando - um rápido olhar para o homem não está me dizendo nada
Yarin

5
@ Yarin - não, e se eu der uma rápida olhada no homem sed, isso também não diz nada. Tente um olhar mais longo.
High Performance Mark

21
A maioria das respostas do SO estão enterradas em algum lugar do homem, mas é isso que SO é o pessoal ocupado que precisa de respostas de pessoas inteligentes
Yarin

9

A resposta do Sinetris está certa, mas eu uso isso com o findcomando para ser mais específico sobre quais arquivos eu quero alterar. Em geral, isso deve funcionar (testado no osx /bin/bash):

find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' {} \;

Em geral, o uso sedsem findprojetos complexos é menos eficiente.


-execé muito legal! Eu só estou querendo saber se a barra no final é realmente precisa
Ye Liu

2
@YeLiu: sem o \, o ;foi interpretado pelo shell quando tentei tal #
serv-inc #

2

Eu criei uma função para lidar com a seddiferença entre o MacOS (testado no MacOS 10.12) e outro sistema operacional:

OS=`uname`
# $(replace_in_file pattern file)
function replace_in_file() {
    if [ "$OS" = 'Darwin' ]; then
        # for MacOS
        sed -i '' -e "$1" "$2"
    else
        # for Linux and Windows
        sed -i'' -e "$1" "$2"
    fi
}

Uso:

$(replace_in_file 's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' "./mysql/.env")

Onde:

, é um delimitador

's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' é padrão

"./mysql/.env" é o caminho para o arquivo


1

Veja como aplicar variáveis ​​de ambiente ao arquivo de modelo (sem necessidade de backup).

1. Crie um modelo com {{FOO}} para substituí-lo posteriormente.

echo "Hello {{FOO}}" > foo.conf.tmpl

2. Substitua {{FOO}} pela variável FOO e envie para o novo arquivo foo.conf

FOO="world" && sed -e "s/{{FOO}}/$FOO/g" foo.conf.tmpl > foo.conf

Trabalhando no macOS 10.12.4 e no Ubuntu 14.04.5


0

Como as outras respostas indicam, não há uma maneira de usar o sed portably no OS X e Linux sem criar arquivos de backup. Então, em vez disso, usei essa linha única do Ruby para fazer isso:

ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml

No meu caso, eu precisava chamá-lo de uma raketarefa (ou seja, dentro de um script Ruby), então usei esse nível adicional de citação:

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}

-1
sed -ie 's/old_link/new_link/g' *

Funciona no BSD e Linux


3
Isso cria no linux outro nome de arquivo com eanexado
Brice

1
Quebrado, melhor para removê-lo.
1616

Está funcionando no Mac e Linux. Qual é o problema com esta solução?
Islam Azab 13/05/19

Não, ele não funciona no Mac BSD Sed - criaria um arquivo de backup com 'e' adicionado ao nome do arquivo.
Jesper Grann Laursen
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.