Чтение строк из файла в массив Bash

Я пытаюсь прочитать файл, содержащий строки, в массив Bash.

Я пробовал следующее:

Attempt1

a=( $( cat /path/to/filename ) )

Attempt2

index=0
while read line ; do
    MYARRAY[$index]="$line"
    index=$(($index+1))
done < /path/to/filename

Обе попытки возвращают только один массив элементов, содержащий первую строку файла. Что я делаю не так?

Я бегу bash 4.1.5

Ответ 1

Последняя версия на основе комментария Комментарий BinaryZebra и здесь. Добавление command eval позволяет удерживать выражение в текущей среде исполнения, а выражения before сохраняются только на протяжении eval.

Используйте $IFS, у которого нет пробелов \tabs, только символы новой строки /CR

$ IFS=$'\r\n' GLOBIGNORE='*' command eval  'XYZ=($(cat /etc/passwd))'
$ echo "${XYZ[5]}"
sync:x:5:0:sync:/sbin:/bin/sync

Также обратите внимание, что вы можете настроить массив просто отлично, но неправильно его прочитать - обязательно используйте как двойные кавычки "", так и скобки {}, как в приведенном выше примере


Edit:

Обратите внимание на множество предупреждений о моем ответе в комментариях о возможном расширении glob, особенно gniourf-gniourf comments о моих предыдущих попытках обойти

Учитывая все эти предупреждения, я все еще оставляю этот ответ здесь (да, bash 4 уже много лет, но я помню, что некоторые маки только 2/3 года имеют pre-4 в качестве оболочки по умолчанию)

Другие примечания:

Можно также следовать приведенному ниже предложению drizzt и заменить раздвоенную подоболочку + cat с помощью

$(</etc/passwd)

Другая опция, которую я иногда использую, - это просто установить IFS в XIFS, а затем восстановить после. См. Также Sorpigal answer, который не нужно беспокоиться об этом

Ответ 2

Команда readarray (также записанная как mapfile) была введена в bash 4.0.

readarray a < /path/to/filename

Ответ 3

Самый простой способ прочитать каждую строку файла в массиве bash:

IFS=$'\n' read -d '' -r -a lines < /etc/passwd

Теперь просто проиндексируйте массив lines для извлечения каждой строки, например

printf "line 1: %s\n" "${lines[0]}"
printf "line 5: %s\n" "${lines[4]}"

# all lines
echo "${lines[@]}"

Ответ 4

Один альтернативный способ, если файл содержит строки без пробелов с 1-й строкой каждой строки:

fileItemString=$(cat  filename |tr "\n" " ")

fileItemArray=($fileItemString)

Check:

Печать всего массива:

${fileItemArray[*]}

Length=${#fileItemArray[@]}

Ответ 5

Ваша первая попытка была близка. Вот простой подход, использующий вашу идею.

file="somefileondisk"
lines=`cat $file`
for line in $lines; do
        echo "$line"
done

Ответ 6

#!/bin/bash
IFS=$'\n' read  -d'' -r -a inlines  < testinput
IFS=$'\n' read  -d'' -r -a  outlines < testoutput
counter=0
cat testinput | while read line; 
do
    echo "$((${inlines[$counter]}-${outlines[$counter]}))"
    counter=$(($counter+1))
done
# OR Do like this
counter=0
readarray a < testinput
readarray b < testoutput
cat testinput | while read myline; 
do
    echo value is: $((${a[$counter]}-${b[$counter]}))
    counter=$(($counter+1))
done