How to print vector formatted in Shell?

Asked

Viewed 187 times

2

I’m trying to get a string and change only one of its values, and that’s easy using vectors. However, when printing the string, the vector leaves without formatting, I have tried to print it with quotes and still it continues with formatting different from the initial, respecting only the formatting of the part I changed.

#!/bin/bash
STR="O    331  RATO    ROEU A  ROUPA      68.352  47.294  40.713  1.00 16.48    C"
IFS='  ' read -r -a array <<< "$STR"
if [ ${array[1]} -gt 99 ] && [ ${array[1]} -lt 999 ] 
then
    array[1]="      1"

fi
echo "${array[@]}"

The way out is:

O       1 RATO ROEU A ROUPA 68.352 47.294 40.713 1.00 16.48 C

But I need the way out:

O       1  RATO    ROEU A  ROUPA      68.352  47.294  40.713  1.00 16.48    C

1 answer

3


The problem is that when creating the array, you separate the string into several elements (one containing the O, another containing 331, etc.), but the spaces are lost. When trying to print the array again, he has no way of knowing how many spaces they had previously (he will only print the elements, separating them by a space).

An alternative is not to break the string into an array, and extract only the snippet you want and replace it:

#!/bin/bash
STR="O    331  RATO    ROEU A  ROUPA      68.352  47.294  40.713  1.00 16.48    C"
VAL=$(echo "$STR" | awk '{print $2}')
if [ $VAL -gt 99 ] && [ $VAL -lt 999  ] 
then
    STR=$(echo "$STR" | sed "s/${VAL}/      1/")
fi
echo "$STR"

The awk breaks the string into multiple parts, separated by space, and allows you to manipulate them the way you need to. In case I’m only taking the second part (print $2), which corresponds to the 331.

Then I test the value of this and do the substitution in the original string, using sed, that changes the value 331 number 1 with multiple spaces before. Finally, just print the string. The result is:

O          1  RATO    ROEU A  ROUPA      68.352  47.294  40.713  1.00 16.48    C

Note that the sed replaced the 331 for "1 with multiple spaces before". But if you just want to exchange 331 for 1 and keep the same amount of spaces, just do:

STR=$(echo "$STR" | sed "s/${VAL}/1/")

Another way to do it is to use grep to pick up either the spaces, or one of the "words" (anything other than space), and go concatenating the resulting strings (replacing only the one you need):

STR="O    331  RATO    ROEU A  ROUPA      68.352  47.294  40.713  1.00 16.48    C"
IFS=$'\n'
RES=""
i=1
for s in $(echo "$STR" | grep -oE ' +|[^ ]+')
do
    if [ $i -eq 3 ] && [ $s -gt 99 ] && [ $s -lt 999 ]
    then
        s='1'
    fi

    RES="$RES$s"
    i=$((i+1))
done
echo "$RES"

The grep uses regular expression ' +|[^ ]+' (one or more spaces or one or more characters that are not spaces), and returns each of these passages separately (first the O, then the spaces, then the 331, the spaces, etc).

The for goes through those results, but I had to change the IFS for him to consider the line break (\n) as separator, so the for also considers spaces as elements when iterating through results.

Within the for I replace only the field I want, and the rest remains the same (including spaces), and I concatenate everything into the variable RES.

The result is the same:

O    1  RATO    ROEU A  ROUPA      68.352  47.294  40.713  1.00 16.48    C

Browser other questions tagged

You are not signed in. Login or sign up in order to post.