2

I have a file containing numbers in it say numbers.txt as follows.

9374541632553  
51243747879841  
32030098896914  
84654557358238  
11000656847765

I want to convert it to the following format.

<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"

I'am using following command to convert it.

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

But output I'am getting is as follows:

<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

Anyone can you please tell me why only 1st line is getting printed at last column instead of line by line value.
And what about 1st line in output?
Explain the required command to desired output.

5 Answers 5

1

You can do it without loop in awk:

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

Output:

<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"

Explanation:

  • first we store first field $1 in variable a
  • substitute each character in $1 with itself followed by space
  • and finally print everything in desired order.
  • a little tricky part is printing double quotes where \" should be quoted itself

Edit (removing last space):

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"
3
  • can u please explain the above awk command ....I mean how it works
    – AVJ
    Jul 31, 2015 at 4:57
  • what if we want to remove space between last number and word '<tag><out>'
    – AVJ
    Jul 31, 2015 at 10:20
  • @AVJ see the edit for explanation, to remove last space just use printf instead of print and hit backspace \b.
    – jimmij
    Jul 31, 2015 at 10:45
1

Because both read and sed are taking data from stdin.

In the while loop, you read the first line into $line. Then sed starts: you don't give it any other input so it reads from stdin, which is the output of cat numbers.txt. So sed will consume the rest of the input. And since you're still in the first iteration of the while loop, the $line variable doesn't change

I'd use perl for this:

perl -lne '($spaced = $_) =~ s/./$& /g; print qq{<item>$spaced<tag>out="$_"}' numbers.txt
1
  • thanks for your explanation.. it helped me to understand...Also by your command i can achieve desired output.
    – AVJ
    Jul 31, 2015 at 4:55
1

Here's one way you might be able to do the whole thing in sed:

sed '
    h; 
    s/./& /g;
    s/.*/<item>&<tag>out=/;
    G;
    s/\n\([0-9]*\)/"\1"/;
    ' numbers.txt
1
  • 1
    Removing regexp speed up script more then 25% h; s/./& /g; s/^/<item>/; G; s/\n\(.*\)/<tag>out="\1"/
    – Costas
    Jul 30, 2015 at 21:08
1

I would think the quickest way to do it would look something like...

sed -e's/./& /g;i\' -e'<item>' \
    -ea\\ -e'<tag><out>=' <file |
paste -d'\0 ""' - - - ./file /dev/null

This also works:

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

How about this...

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

Or,

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .