Como funciona esse comando de substituição 'sed' com muitos sinais @?

8

Alguém pode explicar como esse comando sed funciona?

sed 's@+@ @g;s@%@\x@g' | xargs -0 printf "%b"
    
por Raj 04.10.2017 / 10:13

3 respostas

15

No sed, os comandos substitutos geralmente são gravados como s/pattern/replacement/options . No entanto, não é necessário usar / - você pode usar outros caracteres, se for conveniente, por isso pode ser s@pattern@replacement@options ou s:foo:bar:g . s@+@ @g é como s/+/ /g - substitua todos os + por espaços. Da mesma forma, s@%@\x@g substitui todo % por \x (uma única barra invertida é um caractere de escape no sed, portanto, você precisa de dois para obter uma barra invertida real).

Uma string como foo+%2Fbar se tornará foo \x2Fbar . printf "%b" expandirá as sequências com escape de barra invertida como \x2F (o caractere ASCII cujo valor hexadecimal é 2F, que é / ) para finalmente fornecer foo /bar .

    
por muru 04.10.2017 / 10:32
10

O comando que você está pedindo para decodificar + es e % sequências dos URLs é não apenas um comando sed , é um canal que processa entradas com sed , então canaliza para xargs para processamento adicional. Primeiro vamos ver o comando sed :

sed 's@+@ @g;s@%@\x@g'

Você pode estar mais acostumado a vê-lo com / em vez de @ como separador, o que poderia facilmente ter sido feito aqui sem complicação, pois / não aparece em nenhum dos padrões de pesquisa nem em nenhum dos textos de substituição . Este comando é equivalente:

sed 's/+/ /g;s/%/\x/g'

Como / , @ é um caractere de pontuação perfeitamente bom para sed .

Em cada linha de entrada:

  1. s@+@ @g ( s/+/ /g ) substitui ocorrências ( s ) de + por um espaço. Isso afeta todos os + es em uma linha ( g ), não apenas o primeiro.

  2. ; termina a ação ("comando") e permite que você especifique outra no mesmo "script".

  3. s@%@\x@g ( s/%/\x/g ) substitui ocorrências ( s ) de % com \x . Como antes, ele age em todos ao invés de apenas no primeiro de cada linha ( g ).

    Em \x , o \ representa apenas um \ porque \ tem um significado especial para sed . Seu significado especial é, na verdade, como o personagem que você usa para tirar o significado especial de outro personagem que vem depois dele que, de outra forma, teria um significado especial. Então deve ser escapado como \ .

Agora vamos ver o comando xargs , cuja finalidade é executar printf .

xargs constrói linhas de comando. Se você executar xargs command... , em que command... é uma ou mais palavras, xargs executa command... com argumentos da linha de comando lidos a partir de sua entrada. Nesse caso, a entrada para xargs é a saída de sed , por causa do canal ( | ). Normalmente, xargs interpreta qualquer espaço em branco em sua entrada para significar que o texto antes e depois constitui argumentos separados, mas a opção -0 faz com que ele divida os argumentos nas ocorrências da caractere nulo em vez disso.

No uso pretendido do seu comando, um caractere nulo não aparecerá e xargs executará printf %b com apenas um argumento de linha de comando adicional, a saída do sed comando. Assim, embora não seja equivalente em geral, neste caso, todo o pipeline poderia ter sido escrito assim usando substituição de comando em vez de xargs :

printf '%b\n' "$(sed 's/+/ /g;s/%/\x/g')"

Quanto ao que printf pretende fazer aqui, como diz muru O especificador de formato %b consome e imprime um argumento (como %s ), mas causa escapes de barra invertida - da ordem em que o comando sed no lado esquerdo do canal foi gravado para gerar - para ser translated para os personagens que eles representam .

Suponha que eu execute esse comando e passe http://foldoc.org/debugging%20by%20printf como entrada. Eu recebo http://foldoc.org/debugging by printf como saída, porque as seqüências %20 são traduzidas em espaços.

    
por Eliah Kagan 04.10.2017 / 11:31
3

Essa é a beleza de sed , ela aplica seus paradigmas a si mesma ... Após o comando (como s ou tr ou nada), o próximo caractere é considerado o separador.

Você deve escolher sabiamente para evitar interferência com o shell e com o comando em si, e manter a coisa legível, mas é perfeitamente válido escrever algo tão horrível quanto:

echo 'arrival' | sed srarbrg

... e obtenha brrivbl como resultado, que é o que você espera. Você pode se divertir fazendo isso realmente enigmático, como em:

echo 'arrival' | sed s\fa\fb\fg   # \f is form feed, chr(12)

O uso comum é usar a barra como delimitador, mas quando sua expressão contém o delimitador, fica mais fácil capturar qual é a intenção. Seu delimitador pode ser qualquer coisa no intervalo ASCII8 (delimitadores multibyte, como £ , provocam um erro).

Apenas lembre-se de que o objetivo é tornar as coisas mais fáceis, não mais enigmáticas.

    
por Marabiloso 04.10.2017 / 16:12