views:

55

answers:

4

I'm trying to extract fields from a pipe-delimited file and provide them as arguments to an external program in a loop. The file contains lines like this:

value1|value2
value3|value4

So I came up with:

 while read line;

    do echo -n "${line}" | awk -F '|' '{print $1}';
       echo -n " something ";
       echo -n "${line}" | awk -F '|' '{print $2}';
       echo " somethingelse";

 done < <(cat $FILE)

I want to see the following output:

value1 something value2 somethingelse
value3 something value4 somethingelse

But instead I'm getting:

value1 
 something value2
 somethingelse
value3
 something value4
 somethingelse

Perhaps I shouldn't be using echo?

+2  A: 

If your awk supports printf, I would use that instead. Even though echo -n doesn't add a newline, awk {print} does. The printf variant will not put the newline at the end like print does:

echo -n "${line}" | awk -F '|' '{printf "%s", $1}'

Here's your version hex-dumped, note the \n at the end when you pass it through awk:

pax> echo -n "hello|goodbye" | od -xcb
0000000    6568    6c6c    7c6f    6f67    646f    7962    0065
          h   e   l   l   o   |   g   o   o   d   b   y   e
        150 145 154 154 157 174 147 157 157 144 142 171 145
0000015

pax> echo -n "hello|goodbye" | awk -F '|' '{print $1}' | od -xcb
0000000    6568    6c6c    0a6f
          h   e   l   l   o  \n
        150 145 154 154 157 012

and here's the printf version:

pax> echo -n "hello|goodbye" | awk -F '|' '{printf "%s", $1}' | od -xcb
0000000    6568    6c6c    006f
          h   e   l   l   o
        150 145 154 154 157

And here it is, running on your real file (named FILE in this example to ease my testing):

pax> while read line;
     do
         echo -n "${line}" | awk -F '|' '{printf "%s", $1}';
         echo -n " something ";
         echo -n "${line}" | awk -F '|' '{printf "%s", $2}';
         echo " somethingelse";
     done < <(cat FILE)

value1 something value2 somethingelse
value3 something value4 somethingelse
paxdiablo
Bingo! Thanks for the detailed explanation as well!
A: 

You can use sed for this:

$ cat test
value1|value2
value3|value4
$ sed 's/|/ something /; s/$/ somethingelse/' test
value1 something value2 somethingelse
value3 something value4 somethingelse
$

Update: For your original question, you can remove newlines with tr -d '\012', e.g.

cat ${FILE} | while read line
do
        echo "${line}" | awk -F '|' '{print $1}' | tr -d '\012'
        echo -n " something "
        echo "${line}" | awk -F '|' '{print $2}' | tr -d '\012'
        echo " somethingelse"
done
hlovdal
no need to use `cat`
ghostdog74
+1  A: 

@OP, there's no need to use cat. Also in the while loop, you can set IFS (input field separator) to pipe |, and there's no need to use external commands for every line parsed. It's inefficient. Here's how to do it with just the shell

while IFS="|" read -r a b
do
   echo "$a something $b somethingelse" # use echo without -n
done <"file"

you can also use printf which is more portable than echo.

output

$ ./shell.sh
value1 something value2 somethingelse
value3 something value4 somethingelse
ghostdog74
A: 
while read line;
    do
            echo  "${line}" | sed  s/'|'/' something '/| sed  s/$/' somethingelse'/;
 done < file1
muruga