7

In my file mytxt:

field1                    field2
------                    -------
this are numbers          12345
this letters              abc def ghi 

Let's say I want to store the first field in an array:

i=0
while read line; do 
    field_one[$i]=$(echo $line | awk '{print $1}')
    echo ${field_one[i]}  
    ((i++))
done < mytxt

That would give me the this two times in the output.

Any ideas of how could I store them in an array and get the output:

this are numbers
this letters

I have tried changing delimiters, squeezing spaces, and using sed, but I'm stuck. Any hint would be appreciated.

My final goal is to store both fields in an array.

  • 3
    Something like awk -F ' +' '{print $2}' mytxt.txt? For programming questions stackoverflow is more suitable. – Pablo Bianchi Dec 8 '19 at 3:27
  • 1
    @PabloA and other potential Close voters: We have many questions about bash, grep, arrays, strings and read loops in Ask Ubuntu. If this question is off-topic then all those other questions would also be off-topic (which I don't think they are). Ironically you are suggesting the solution is with awk and then deeming your solution to be off-topic and by inference the question as well. But there are other ways of solving the problem without awk. – WinEunuuchs2Unix Dec 8 '19 at 16:02
  • Can you clarify exactly how the fields are defined? It looks like they're fixed-width fields, separated by lots of spaces; is that correct? Can the field width change (i.e. does it have to be inferred by the spacing of the headers)? Also, note that using variables without double-quotes has bad effects, so use e.g. echo "$line" instead of just echo $line. – Gordon Davisson Dec 8 '19 at 19:48
  • Thank you for all your answers guys I will review them all! – zou hai Dec 8 '19 at 22:39
  • 1
    Pablo A got the simplest solution for a begginer like me thanks! – zou hai Dec 8 '19 at 22:48
2

Moving my comment, based on this source, to just show a particular column on multiple-spaces based table:

awk -F '  +' '{print $2}' mytxt.txt  # Or with -F ' {2,}'

Note that this won't work if you use double quotes.

I found it particularly useful to find duplicates, using something like:

somelist... | sort | uniq -c | sort -rn | grep -vP "^ +1 " | awk -F '  +' '{print $3}'
4

Using colrm to remove columns from file.

#!/bin/bash

shopt -s extglob

a=()
while read; do
   a+=("${REPLY%%*( )}")
done < <(colrm 26 < text.txt)

printf %s\\n "${a[@]:2:3}"

(Bash builtin version):

#!/bin/bash

shopt -s extglob

a=()
while read; do
    b="${REPLY::26}"; a+=("${b%%*( )}")
done < text.txt

printf %s\\n "${a[@]:2:3}"
2

You could use the bash builtin mapfile (aka readarray) with a callback that uses parameter expansion to trim the longest trailing substring starting with two spaces:

mapfile -c 1 -C 'f() { field_one[$1]="${2%%  *}"; }; f' < mytxt

Ex. given

$ cat mytxt
field1                    field2
------                    -------
this are numbers          12345
this letters              abc def ghi 

then

$ mapfile -c 1 -C 'f() { field_one[$1]="${2%%  *}"; }; f' < mytxt
$
$ printf '%s\n' "${field_one[@]}" | cat -A
field1$
------$
this are numbers$
this letters$
  • 2
    nice real-world example of the mapfile callback :)= – bac0n Dec 8 '19 at 13:49
  • 1
    @bacon do you know of a way to use the callback to modify what gets assigned to the MAPFILE array itself? I couldn't find one - which seems like a rather serious limitation (my answer effectively creates two arrays and discards one) – steeldriver Dec 8 '19 at 14:01
  • 1
    callback is evaluated after the line is read but before the array element is assigned, so its not possible. – bac0n Dec 8 '19 at 15:07
  • 1
    I presume "${2%% *}" grabs everything before two spaces? If field 1 was long such that there was only one space separating it from field 2 would the code break? – WinEunuuchs2Unix Dec 8 '19 at 16:22
  • 1
    @WinEunuuchs2Unix it would break if the undesired portion is not separated by at least 2 spaces - or if the desired portion contains a sequence of 2 or more spaces. Fundamentally the inter- and intra-field delimiters need to be distinguishable in some way. – steeldriver Dec 8 '19 at 16:26
2

This answer focuses on removing two heading lines from the array to match output requirements.

$ cat fieldone.txt
field1                    field2
------                    -------
this are numbers          12345
this letters              abc def ghi 

$ fieldone
this are numbers         
this letters             

Here is the script:

#!/bin/bash

# NAME: fieldone
# PATH: $HOME/askubuntu/
# DESC: Answer for: https://askubuntu.com/questions/1194620/
# how-would-you-separate-fields-with-multiple-spaces-and-store-them-in-an-array

# DATE: December 8, 2019.

i=0                                     # Current 0-based array index number
while read line; do                     # Read all lines from input file
    ((LineNo++))                        # Current line number of input file
    [[ $LineNo -eq 1 ]] && continue     # "Field 1     Field 2" skip first line
    if [[ $LineNo -eq 2 ]] ; then       # Is this is line 2?
        # Grab the second column position explained in:
        # https://unix.stackexchange.com/questions/153339/
        # how-to-find-a-position-of-a-character-using-grep
        Len="$(grep -aob ' -' <<< "$line" | \grep -oE '[0-9]+')"
        continue                        # Loop back for first field
    fi

    field_one[$i]="${line:0:$Len}"      # Extract line position 0 for Len
    echo "${field_one[i]}"              # Display array index just added
    ((i++))                             # Increment for next array element

done < fieldone.txt                     # Input filename fed into read loop

Hopefully code and comments are self explanatory. If not don't hesitate to comment.

The script still works if only one space separates the two columns whereas some other answers will break:

field1         field2
------         ------
this is letter abcdef
this is number 123456

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.