Читать разделенную табуляцией строку файла в массив

Я хотел бы прочитать файл в сценарий, строка за строкой. Каждая строка в файле состоит из нескольких значений, разделенных вкладкой, я хотел бы прочитать каждую строку в массив.

Типичный пример bash "чтение файла за строкой";

while read line
do
echo $line;
done < "myfile"

Для меня myfile выглядит так (значения, разделенные табуляцией);

value1 value2 value3
value4 value5 value6

На каждой итерации цикла я бы хотел, чтобы каждая строка входила в массив, чтобы я мог

while read line into myArray
do
 echo myArray[0]
 echo myArray[1]
 echo myArray[2]
done < "myfile"

Это напечатало бы следующее на первой итерации цикла;

value1
value2
value3

Затем на второй итерации будет напечатано

value4
value5
value6

Это возможно? Единственный способ увидеть это - написать небольшую функцию для ручного разбора значений. Есть ли в bash встроенная поддержка для этого?

Ответ 1

Вы очень близки:

while IFS=$'\t' read -r -a myArray
do
 echo "${myArray[0]}"
 echo "${myArray[1]}"
 echo "${myArray[2]}"
done < myfile

(-r сообщает read, что \ не является специальным во входных данных, -a myArray сообщает ему разбить строку ввода на слова и сохранить результаты в myArray, а IFS=$'\t' указывает, что он использует только вкладки для разделения слов вместо обычного стандартного значения Bash, также позволяя пробелам также разделить слова. Обратите внимание, что этот подход будет обрабатывать одну или несколько вкладок в качестве разделителя, поэтому, если какое-либо поле пустые, более поздние поля будут "сдвинуты" на более ранние позиции в массиве. Это нормально?)

Ответ 2

Если вы действительно хотите разбить каждое слово (bash значение) на другой индекс массива, полностью изменяющий массив в каждой итерации цикла while, правильный ответ. Но вы можете использовать свойство read для разбиения каждого прочитанного слова на разные переменные column1, column2, column3, как в этом фрагменте кода

while IFS=$'\t' read -r column1 column2 column3 ; do
  printf "%b\n" "column1<${column1}>"
  printf "%b\n" "column2<${column2}>"
  printf "%b\n" "column3<${column3}>"
done < "myfile"

чтобы достичь аналогичного результата, избегая доступа к индексу массива и улучшая читаемость кода с использованием значимых имен переменных (конечно, использование columnN не рекомендуется делать).

Ответ 3

Вы также можете попробовать,

OIFS=$IFS;
IFS="\t";

animals=`cat animals.txt`
animalArray=$animals;

for animal in $animalArray
do
    echo $animal
done

IFS=$OIFS;