imprimiu o mesmo valor, mas na verdade o valor é diff

1

a seguinte sintaxe usada para capturar a palavra entre no arquivo xml Eu também uso o xargs para remover qualquer espaço

var=' find /tmp -name '*.xml' -exec sed -n 's/<Name>\([^<]*\)<\/Name>//p' {} +  |  xargs '

echo $var
TOPIC

até agora parece estar ok

mas printf mostra outra coisa

printf "%q\n" "$var"
$'TOPIC\r'

permite detalhar

[[ TOPIC == $var ]] && echo they are equal

não impresso "eles são iguais

mas quando imprimimos $ var, obtemos

echo $var
TOPIC

então depois que as coisas parecem claramente

a grande pergunta é:

como remover os caracteres extras ($, \ r) da variável -

$'TOPIC\r'
    
por yael 17.01.2018 / 12:38

2 respostas

4

Esse $'TOPIC\r' é uma representação visual dada pela sua implementação printf para representar o conteúdo dessa variável. Ele usa a forma de cota $'...' do ksh93 (agora também suportada por zsh , bash e alguns outros shells) para dar a você essa representação. Nesses shells, var=$'TOPIC\r' criaria uma variável $var com o mesmo conteúdo. Nessa forma de cotação, \r representa um caractere de retorno de carro.

Esse é um caracter que, quando enviado para um terminal, faz com que o terminal mova o cursor para o início da linha. É um caractere de controle para o terminal, não é um caractere normal com um glifo associado a ele.

printf 'ABC\rX\n'

( printf , no seu argumento formato também reconhece \r como significando um caractere CR) é exibido como:

XBC

Se você escrever:

printf 'ABC\rX\n' | pv -qL3

para diminuir a velocidade, você pode ver o que acontece.

Para removê-lo, com shells semelhantes ao ksh93 (ksh93, zsh, bash ou mksh), você pode fazer

var=${var//$'\r'}

\r também é classificado como um caractere [:space:] . Então você também pode remover todos os caracteres de espaçamento com:

var=${var//[[:space:]]}

Para remover apenas o caractere CR (aquele no final da variável):

var=${var%$'\r'}

(que deve ser portável para mais alguns shells).

POSIXly (como em scripts sh portáteis), você pode fazer:

var=$(printf %s "$var" | tr -d '\r')

Embora note que também removeria caracteres newline (também conhecidos como linefeed aka LF aka \n ) do final do conteúdo da variável.

Como observação, [[ TOPIC = $var ]] (também ksh ism também suportado por zsh e bash) é um operador de correspondência de padrões, não um operador de teste de igualdade (exceto em zsh quando não está emulando ksh / bash) você precisa de [[ TOPIC = "$var" ]] para testar a igualdade, var=*; [[ TOPIC = $var ]] retornaria verdadeiro por exemplo (e var='[x]'; [[ $var = $var ]] retornaria falso ).

Lembre-se também de que echo não pode ser usado para gerar dados arbitrários e expansões de parâmetros geralmente devem ser citados .

$ var=$'TOPIC\r'
$ printf '%s\n' "$var" # zsh (my shell) builtin
TOPIC
$ printf '%q\n' "$var"
TOPIC$'\r'
$ /usr/bin/printf '%q\n' "$var" # GNU printf
'TOPIC'$'\r'
$ (export var; bash -c 'printf "%q\n" "$var"') # bash builtin
$'TOPIC\r'
$ (export var; ksh93 -c 'printf "%q\n" "$var"') # ksh93 builtin
$'TOPIC\r'
$ (export var; dash -c 'printf "%q\n" "$var"')
dash: 1: printf: %q: invalid directive

%q não é uma diretiva printf padrão, nem todas as implementações o suportam e o comportamento varia entre implementações que o fazem. sed -n l é uma maneira portátil / padrão de obter representações visuais não ambíguas de strings (embora a saída também varie entre implementações):

$ printf '%s\n' "$var" | sed -n l
TOPIC\r$

Esse $ é para mostrar o final da linha (útil para linhas que possuem espaços à direita).

$ var=${var//$'\r'}
$ printf '%s\n' "$var" | sed -n l
TOPIC$
    
por 17.01.2018 / 13:37
2

A \r é uma notação herdada de C e significa um retorno de carro. Seu arquivo provavelmente tem terminações de linha CRLF no estilo DOS / Windows. sed e xargs consideram o CR apenas outro caractere e é transmitido. Embora qualquer outra coisa na mesma linha, fora das tags <Name>...</Name> , também seria transmitida por esse sed.

$ echo 'foo <Name>bar</Name><Num>123</Num>' | sed 's/<Name>\([^<]*\)<\/Name>//'
foo bar<Num>123</Num>

Se você estiver escolhendo campos de um arquivo XML como esse, convém remover sed de qualquer coisa ao redor da linha ao mesmo tempo:

$ echo 'foo <Name>bar</Name><Num>123</Num>' | sed 's/.*<Name>\([^<]*\)<\/Name>.*//'
bar

Isso também deve eliminar qualquer CR no final, já que eles correspondem ao .* .

    
por 17.01.2018 / 14:50