isb
isb

Reputation: 53

read -r is wrongly breaking the file fields

I have file named fields ,which should contained 4 fields

Example filed from the file:

rhel-x86_64-server-7 string1_string2_string4 STRING5  STRING6 7 STRING6 64-bit 2016-06-13

in the beginning there was 3 fields in the file without the date filed at the end ,like this:

rhel-x86_64-server-7 string1_string2_string4 STRING5  STRING6 7 STRING6 64-bit

once I had the 3 fields file ,I have created a while read loop to read the lines one by one and give me 3 variables

while read -r  filed1  filed2 filed3 ;do
    echo "$filed1"
    echo "$filed2"
    echo "$filed3

So if I echo those fields I was getting:

rhel-x86_64-server-7
string1_string2_string4
TRING5  STRING6 7 STRING6 64-bit

but when I added the forth filed to the file (the date filed) and added the forth variable to the while loop , IE:

while read -r  filed1  filed2 filed3 filed4 ;do

when echoing , I am getting something like that:

rhel-x86_64-server-7
string1_string2_string4 
STRING5 
STRING6 7 STRING6 64-bit 2016-06-13

I am expecting to get the following lines:

rhel-x86_64-server-7
string1_string2_string4
STRING5 STRING6 7 STRING6 64-bit  
2016-06-13

Can you please suggest how to achieve that?

Upvotes: 0

Views: 55

Answers (3)

chepner
chepner

Reputation: 530853

The simplest thing to do would be to read the values into an array instead, then use substring expansion to gather the desired fields together.

read -r -a fields
field1=${fields[0]}
field2=${fields[1]}
field3=${fields[@]:2:${#fields[@]}-5}
field4=${fields[-1]}

Upvotes: 2

janos
janos

Reputation: 124648

in the beginning there was 3 fields in the file without the date filed at the end ,like this:

rhel-x86_64-server-7 string1_string2_string4 STRING5  STRING6 7 STRING6 64-bit

It's not clear what 3 fields you're talking about. For your information Bash sees the fields like this:

  1. rhel-x86_64-server-7
  2. string1_string2_string4
  3. STRING5
  4. STRING6
  5. 7
  6. STRING6
  7. 64-bit

And notice in help read:

One line is read from the standard input, or from file descriptor FD if the
-u option is supplied, and the first word is assigned to the first NAME,
the second word to the second NAME, and so on, with leftover words assigned
to the last NAME.  [...]

Especially the last part, leftover words assigned to the last NAME. This is why STRING5 STRING6 7 STRING6 64-bit were all stored in the same variable, filed3, not because these are in one field, but because these are the leftovers.

If you want to chop off the last field delimited by a space, pattern substitution might help:

while read -r f1 f2 f3; do
    echo "$f1"
    echo "$f2"
    echo "${f3% *}"
    echo "${f3##* }"

${f3% *} is f3 with everything chopped off after the last space.

${f3##* } is f3 with everything chopped off until the last space.

Output for your example input:

rhel-x86_64-server-7
string1_string2_string4
STRING5  STRING6 7 STRING6 64-bit
2016-06-13

Upvotes: 2

arnabkaycee
arnabkaycee

Reputation: 1644

For many command line interpreters (“shell”) of Unix operating systems, the internal field separator (abbreviated IFS) refers to a variable which defines the character or characters used to separate a pattern into tokens for some operations.

IFS typically includes the space, tab, and the newline.

In your case IFS=" " [blank space],

So, by default the fields are getting separated by space.

Usage of IFS:

IFS=' ' read -p 'Enter your first and last name : ' first last 
echo "Hello, $first $last"

Sample Output:

Enter your first and last name : Vivek Gite
Hello, Vivek Gite

Please use a consistent field separator to get the results you desire.

Upvotes: 0

Related Questions