Simples substituição de sed de abas misteriosamente falhando

33

Isso deve ser realmente simples, mas, por algum motivo, não está funcionando:

sed -i.bak -E 's/\t/  /' file.txt

Em vez de substituir os caracteres de tabulação, ele substitui os caracteres t . Eu tentei todas as variações sobre isso que eu poderia pensar, brincando com citações, etc. Eu pesquisei e encontrei todos os outros usando expressões bastante semelhantes e eles parecem funcionar para eles.

O -E é uma coisa do OS X. Eu pensei que a falha poderia ser resultado de alguma estranha peculiaridade do sed do OS X, então eu tentei com Ruby também (sem o -i ), e obtive o mesmo resultado:

ruby -pe '$_.gsub!(/\t/,"  ")' < file.txt > file.new

Estou usando o Bash 3.2.51 no OS X e o iTerm, embora não consiga ver como isso pode ser muito relevante. Eu não defini nenhuma variável de ambiente estranha, apesar de poder postar algo que você acha que pode ser relevante.

O que poderia estar errado?

UPDATE : Eu devo ter cometido algum outro erro ou erro de digitação quando experimentei a versão em Ruby, já que Gilles aponta que faz (e eu nunca o fiz me enganar!). Não tenho certeza do que aconteceu, mas tenho certeza que deve ter sido meu erro.

    
por iconoclast 18.07.2014 / 16:15

7 respostas

51

A sintaxe \t para um caractere de tabulação no sed não é padrão. Essa fuga é uma extensão de GNU sed . Você encontra muitos exemplos on-line que o utilizam porque muitas pessoas usam o GNU sed (é a implementação do sed no Linux não integrado). Mas OS X sed , como outros * BSD sed , não suporta \t para a guia e, em vez disso, trata \t como significando barra invertida seguida por t .

Existem muitas soluções, como:

  • Use um caractere de tabulação literal.

    sed -i.bak 's/  /  /' file.txt
    
  • Use tr ou printf para produzir um caractere de guia.

    sed -i.bak "s/$(printf '\t')"/  /' file.txt
    sed -i.bak "s/$(echo a | tr 'a' '\t')"/  /' file.txt
    
  • Use a sintaxe de string do bash que permite a saída de barras invertidas .

    sed -i.bak $'s/\t/  /' file.txt
    
  • Use Perl, Python ou Ruby. O snippet Ruby que você postou funciona.

por 19.07.2014 / 01:02
13

Use uma citações específica do Bash que permita usar strings como em C, para que um caractere de tabulação real seja passado para sed, não uma seqüência de escape:

sed -i.bak -E $'s/\t/  /' file.txt
    
por 18.07.2014 / 18:31
1

Como observado, nem todas as implementações sed suportam a notação de \t como uma guia horizontal.

Você pode facilmente conseguir sua substituição com:

 perl -pi.old -e 's{\t+}{ }g' file.txt

Isto realiza uma substituição in situ que preserva seu arquivo original como "* .old". Perl permite delimitadores alternativos para o clássico / , tornando a expressão muito mais legível (ou seja, sem a síndrome do "palito inclinado").

O + diz que uma ou mais repetições de um caractere de tabulação devem ser substituídas. O modificador g permite substituições globais ao longo do final de cada linha.

    
por 18.07.2014 / 17:42
1
sed -i $'s/\t/  /g' file.txt 

funciona para mim no OS X e é o mesmo comando que eu uso no linux o tempo todo.

    
por 04.10.2016 / 20:12
0

Se você quiser um sed (suportando \t e mais) mais poderoso que o do OS X, instale o GNU sed .

    
por 18.07.2014 / 17:31
-1

Estou surpreso que ninguém sugeriu a solução muito simples de:     %código% Isso deve fazer o truque.

Você precisa escapar da fuga (daí os 3 \ s) para permitir que o sed entenda que você está tentando usar um caractere \ t na expressão regular quando tudo é substituído ...

    
por 14.01.2016 / 00:31
-4

Isso funcionou para mim.

sed -e 's / [\ t] / / g'

    
por 26.09.2017 / 21:27