it-roy-ru.com

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

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

Типичный пример 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 встроенная поддержка для этого?

53
jwbensley

Ты очень близко

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 также позволяет разделять слова пробелами. Обратите внимание, что этот подход будет рассматривать одну или более табуляции как разделитель, поэтому, если какое-либо поле будет пустым, более поздние поля будут «смещены» в более ранние позиции в массив. Это нормально?)

117
ruakh

Если вы действительно хотите разделить каждое Слово (значение bash) на другой индекс массива, полностью изменив массив в каждой итерации цикла while, ответ @ ruakh - правильный подход. Но вы можете использовать свойство read для разбиения каждого прочитанного Word на разные переменные 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 не является хорошей идеей для этого).

7
slylittl3

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

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

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

for animal in $animalArray
do
    echo $animal
done

IFS=$OIFS;
0
Dinuksha Samanage