bash expandindo para o mesmo valor em vez do valor de linha por linha no comando sed

2

Eu tenho um arquivo contendo números nele, digamos numbers.txt da seguinte forma.

9374541632553  
51243747879841  
32030098896914  
84654557358238  
11000656847765

Eu quero convertê-lo para o seguinte formato.

<item>9 3 7 4 5 4 1 6 3 2 5 5 3 <tag>out="9374541632553" 
<item>5 1 2 4 3 7 4 7 8 7 9 8 4 1 <tag>out="51243747879841" 
<item>3 2 0 3 0 0 9 8 8 9 6 9 1 4 <tag>out="32030098896914"
<item>8 4 6 5 4 5 5 7 3 5 8 2 3 8 <tag>out="84654557358238"
<item>1 1 0 0 0 6 5 6 8 4 7 7 6 5 <tag>out="11000656847765"

Eu estou usando o seguinte comando para convertê-lo.

cat numbers.txt | while read line; do sed -r "s/([0-9])//g; s/([0-9])/ /g ; s/^/<item>/g; s/$/<tag>out="\$line/g" ; done

Mas a saída que estou recebendo é a seguinte:

<item>5 1 2 4 3 7 4 7 8 7 9 8 4 1 <tag>out="9374541632553
<item>3 2 0 3 0 0 9 8 8 9 6 9 1 4 <tag>out="9374541632553
<item>8 4 6 5 4 5 5 7 3 5 8 2 3 8 <tag>out="9374541632553
<item>1 1 0 0 0 6 5 6 8 4 7 7 6 5 <tag>out="9374541632553
<item>3 3 2 1 6 7 8 2 0 9 3 8 4 2 <tag>out="9374541632553

Alguém pode, por favor, me dizer por que apenas a primeira linha está sendo impressa na última coluna em vez do valor linha por linha.
E quanto à 1ª linha na produção?
Explique o comando necessário para a saída desejada.

    
por AVJ 30.07.2015 / 20:09

5 respostas

1

Você pode fazer isso sem loop em awk :

awk '{a=$1;gsub(/./,"& ",$1); print "<item>"$1"<tag><out>=""\""a"\""}' numbers.txt

Saída:

<item>9 3 7 4 5 4 1 6 3 2 5 5 3 <tag><out>="9374541632553"
<item>5 1 2 4 3 7 4 7 8 7 9 8 4 1 <tag><out>="51243747879841"
<item>3 2 0 3 0 0 9 8 8 9 6 9 1 4 <tag><out>="32030098896914"
<item>8 4 6 5 4 5 5 7 3 5 8 2 3 8 <tag><out>="84654557358238"
<item>1 1 0 0 0 6 5 6 8 4 7 7 6 5 <tag><out>="11000656847765"

Explicação:

  • primeiro armazenamos o primeiro campo $1 na variável a
  • substitua cada caractere em $1 por si mesmo seguido por espaço
  • e finalmente imprima tudo na ordem desejada.
  • uma pequena parte complicada é imprimir aspas duplas onde \" deve ser citado

Editar (remover o último espaço):

awk '{a=$1;gsub(/./,"& ",$1); printf "<item>"$1"\b<tag><out>=""\""a"\"\n"}' numbers.txt

<item>9 3 7 4 5 4 1 6 3 2 5 5 3<tag><out>="9374541632553"
<item>5 1 2 4 3 7 4 7 8 7 9 8 4 1<tag><out>="51243747879841"
<item>3 2 0 3 0 0 9 8 8 9 6 9 1 4<tag><out>="32030098896914"
<item>8 4 6 5 4 5 5 7 3 5 8 2 3 8<tag><out>="84654557358238"
<item>1 1 0 0 0 6 5 6 8 4 7 7 6 5<tag><out>="11000656847765"
    
por 30.07.2015 / 22:37
1

Como read e sed estão recebendo dados de stdin.

No loop while , você read da primeira linha para $line . Então sed começa: você não dá nenhuma outra entrada, então lê de stdin, que é a saída de cat numbers.txt . Portanto, sed consumirá o restante da entrada. E como você ainda está na primeira iteração do loop while, a variável $ line não muda

Eu usaria o perl para isso:

perl -lne '($spaced = $_) =~ s/./$& /g; print qq{<item>$spaced<tag>out="$_"}' numbers.txt
    
por 30.07.2015 / 20:25
1

Aqui está uma maneira de você fazer tudo no sed:

sed '
    h; 
    s/./& /g;
    s/.*/<item>&<tag>out=/;
    G;
    s/\n\([0-9]*\)/""/;
    ' numbers.txt
    
por 30.07.2015 / 20:45
1

Eu acho que a maneira mais rápida de fazer isso seria algo como ...

sed -e's/./& /g;i\' -e'<item>' \
    -ea\ -e'<tag><out>=' <file |
paste -d'
(       set -- - - - - - - /tmp/file
        paste -d'<item> <tag><out>="'  "$@" - - - - - - "$@" |
        sed 's/ *$/"/;s/\([0-9]\) *\(<.*\)*/ /g'
)       </dev/null
""' - - - ./file /dev/null

Isso também funciona:

sed -e's/./& /g;i\' -e'<item>' \
    -ea\ -e'<tag><out>=' <file |
paste -d'
(       set -- - - - - - - /tmp/file
        paste -d'<item> <tag><out>="'  "$@" - - - - - - "$@" |
        sed 's/ *$/"/;s/\([0-9]\) *\(<.*\)*/ /g'
)       </dev/null
""' - - - ./file /dev/null
    
por 30.07.2015 / 23:09
-1

Que tal isso ...

cat numbers.txt | while read line; do echo $line | sed -r "s/([0-9])//g; s/([0-9])/ /g ; s/^/<item>/g; s/$/<tag>out=\"$line\"/g" ; done

Ou

cat numbers.txt | while read line; do echo "<item>$(echo $line | fold -w1 | paste -s -d' ') <tag>out=\"$line\""; done
    
por 30.07.2015 / 20:33