3

I have some code similar to this:

while read -r col1 col2 col3 col4 col5 col6 col7 col8 TRASH; do 
        echo -e "${col1}\n${col2}\n${col3}\n${col4}\n${col5}\n${col6}\n"
done< <(ll | tail -n+2 | head -2)

(I'm not actually using ls / ll but I believe this redacted example displays the same issue I am having)

The problem is I need a conditional statement if ll | tail -n+2 | head -2 fails so I'm trying to create a mapfile instead and then read through it in a script. The mapfile gets created properly but I don't know how to redirect it in order to be properly read.

code

if ! mapfile -t TEST_ARR < <(ll | tail -n+2 | head -2); then
        exit 1
fi
while read -r col1 col2 col3 col4 col5 col6 col7 col8 TRASH; do 
        echo -e "${col1}\n${col2}\n${col3}\n${col4}\n${col5}\n${col6}\n"
done<<<"${TEST_ARR[@]}"

mapfile contents

declare -a TEST_ARR=(
        [0]="drwxr-xr-x@ 38 wheel   1.2K Dec  7 07:10 ./" 
        [1]="drwxr-xr-x  33 wheel   1.0K Jan 18 07:05 ../"
)

output

$ while read -r col1 col2 col3 col4 col5 col6 col7 col8 TRASH; do
>             echo -e "${col1}\n${col2}\n${col3}\n${col4}\n${col5}\n${col6}\n"
>     done<<<"${TEST_ARR[@]}"
drwxr-xr-x@
38
wheel
1.2K
Dec
7

String redirect is clearly wrong in this case but I'm not sure how else I can redirect my array.

jesse_b
  • 37,005

2 Answers2

7

It seems to me that you're wanting to loop through your array, reading the elements into columns:

for ele in "${TEST_ARR[@]}"
do
  read -r col1 col2 col3 col4 col5 col6 col7 col8 TRASH <<< "$ele"
  echo -e "${col1}\n${col2}\n${col3}\n${col4}\n${col5}\n${col6}\n"
done
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
  • Thanks! I wasn't aware I could use read that way and had a method for setting all my variables with awk but it would not have been efficient. This is great! – jesse_b Jan 20 '18 at 01:49
3

mapfile reads the contents of a file to an array, and if you use "${array[@]}" in a context like an assignment or <<< that takes only a single string, it concatenates all the array elements to a single string. A bit like "${array[*]}", except @ joins with spaces, and * with the first character of IFS.

Now, you said you "created a mapfile", but I don't think that's how the command name is supposed to be interpreted. It's more like that it "maps" a file to an array. (Except that it's a copy, not a two-way mapping like it might be in some languages.) The alternative name of readarray is probably more accurate.

ilkkachu
  • 138,973