É portável indentar o argumento para o comando 'i \' do sed?

3

Fiquei com a impressão das especificações POSIX para sed de que é necessário para alinhar à esquerda o texto na linha após o comando i\ , a menos que você queira espaços em branco na saída.

Um teste rápido no meu Mac (usando o BSD sed) mostra que talvez isso não seja necessário :

$ cat test.sed 
#!/bin/sed -f
i\
      This line starts with spaces.
$ echo some text | sed -f test.sed
This line starts with spaces.
some text
$ 

No entanto, parece que não consigo encontrar isto documentado em qualquer lugar. Não está nas especificações do POSIX, e nem na man page do sed no meu sistema.

Posso confiar neste comportamento em sed scripts que eu quero ser portátil? Qual é a sua portabilidade?

(Está documentado em qualquer lugar? )

(Pergunta bônus: é possível até mesmo forçar sed a inserir espaços em branco no início de uma linha fixa passada para i\ ?)

    
por Wildcard 27.09.2016 / 04:08

3 respostas

4

Não, mas o seu script será portátil, desde que você escape de qualquer espaço em branco. Por quê ? Porque alguns sed s retiram caracteres em branco das linhas de texto e a única maneira de evitar isso é escapar do espaço em branco à esquerda, como explicam as páginas de manual do século passado: 1 , 2 , 3
O mesmo vale para BSD sed ( OSX acabou de copiar o código, não é sua extensão) e se você verificar os arquivos e ler o man page de BSD 2.11 é bastante claro:

(1)i\
text
.......
An argument denoted text consists of one or more lines, all but the last of which end with '\' to hide the newline. Backslashes in text are treated like backslashes in the replacement string of an 's' command, and may be used to protect initial blanks and tabs against the stripping that is done on every script line.

Agora, onde isso é documentado na especificação POSIX? Apenas diz

The argument text shall consist of one or more lines. Each embedded <newline> in the text shall be preceded by a <backslash>. Other <backslash> characters in text shall be removed, and the following character shall be treated literally.

e se você rolar para baixo em RATIONALE , ele diz

The requirements for acceptance of <blank> and <space> characters in command lines has been made more explicit than in early proposals to describe clearly the historical practice and to remove confusion about the phrase "protect initial blanks [sic] and tabs from the stripping that is done on every script line" that appears in much of the historical documentation of the sed utility description of text. (Not all implementations are known to have stripped <blank> characters from text lines, although they all have allowed leading <blank> characters preceding the address on a command line.)

Como a parte com "barras invertidas pode ser usada para" não foi incluída nessa citação, a frase restante "protege os espaços em branco iniciais ..." não faz qualquer sentido ... 1

De qualquer forma, para resumir: algumas implementações (e algumas ainda fazem) tiram espaços em branco das linhas de texto. No entanto, uma vez que a especificação POSIX a qual todas as implementações devem obedecer diz

Other <backslash> characters in text shall be removed, and the following character shall be treated literally.

podemos concluir que a maneira portátil de recuar as linhas no texto a ser inserido é escapar da lacuna inicial em cada uma dessas linhas.

1: Eu também não entendo porque OSX / BSD pessoas mudaram o parágrafo inteiro na página man sem alterar o código fonte - você tem o mesmo comportamento de antes, mas o homem seção que documenta este material não está mais lá.

    
por 29.10.2016 / 17:39
2

É a extensão OSX sed , não o comportamento padrão. Você pode ver este link, na função compile_text :

/*
 * Compile the text following an a or i command.
 */
static char *
compile_text()
{
    int asize, size;
    char *text, *p, *op, *s;
    char lbuf[_POSIX2_LINE_MAX + 1];

    asize = 2 * _POSIX2_LINE_MAX + 1;
    text = xmalloc(asize);
    size = 0;
    while (cu_fgets(lbuf, sizeof(lbuf))) {
        op = s = text + size;
        p = lbuf;
        EATSPACE();
        for (; *p; p++) {
            if (*p == '\')
                p++;
            *s++ = *p;
        }
        size 

Eles comeram espaços usando EATSPACE macro.

No FreeBSD sed , que pode tratar incorretamente \ como caracteres de continuação de linha ao usar a , i , c , o comportamento é mais estranho. No meu FreeBSD 9.3:

$ echo 1 | sed -e 'i\ 1'
": extra characters after \ at the end of i command

mas:

$ echo 1 | sed -e 'i\
 2'
2
1

funciona e também come espaços.

GNU sed , a herança sed não tem esse problema.

    
por 27.09.2016 / 04:37
1

Cuonglm deu a melhor resposta , mas para registro está aqui o que GNU sed faz:

echo foo | sed 'i\
     This line starts with spaces.'

Saída:

     This line starts with spaces.
foo
    
por 27.09.2016 / 05:03