Сценарий принимает URL-адрес, анализирует его на наличие обязательных полей и перенаправляет свой вывод для сохранения в файле file.txt . Выходные данные сохраняются в новой строке каждый раз при обнаружении поля.
file.txt
A Cat
A Dog
A Mouse
etc...
Я хочу взять file.txt
и создать из него массив в новом скрипте, где каждая строка должна быть собственной строковой переменной в массиве. Пока я пробовал:
#!/bin/bash
filename=file.txt
declare -a myArray
myArray=(`cat "$filename"`)
for (( i = 0 ; i < 9 ; i++))
do
echo "Element [$i]: ${myArray[$i]}"
done
Когда я запускаю этот скрипт, пробелы приводят к разделению слов и вместо получения
Желаемый результат
Element [0]: A Cat
Element [1]: A Dog
etc...
Я получаю вот что:
Фактический выход
Element [0]: A
Element [1]: Cat
Element [2]: A
Element [3]: Dog
etc...
Как я могу настроить цикл ниже, чтобы вся строка в каждой строке соответствовала один к одному каждой переменной в массиве?
Ответы:
Используйте
mapfile
команду:mapfile -t myArray < file.txt
Ошибка using
for
- идиоматический способ перебора строк файла:while IFS= read -r line; do echo ">>$line<<"; done < file.txt
См. BashFAQ / 005 для более подробной информации.
источник
while IFS= read -r; do lines+=("$REPLY"); done <file
.mapfile
не будет работать должным образом на многих машинах без дополнительных шагов. Macs @ericslaw продолжат поставляться с bash 3.2.57 в обозримом будущем. В более поздних версиях используется лицензия, по которой Apple должна предоставлять или разрешать то, что они не хотят делиться или разрешать.mapfile
иreadarray
(которые являются синонимами) доступны в Bash версии 4 и выше. Если у вас более старая версия Bash, вы можете использовать цикл для чтения файла в массив:arr=() while IFS= read -r line; do arr+=("$line") done < file
Если в файле есть неполная последняя строка (отсутствует новая строка), вы можете использовать эту альтернативу:
arr=() while IFS= read -r line || [[ "$line" ]]; do arr+=("$line") done < file
Связанный:
источник
IFS= read -r line || [[ "$line" ]]
чтобы это работало. В остальном отлично работает!do
?Ты тоже можешь это сделать:
oldIFS="$IFS" IFS=$'\n' arr=($(<file)) IFS="$oldIFS" echo "${arr[1]}" # It will print `A Dog`.
Заметка:
Расширение имени файла все еще происходит. Например, если есть строка с литералом,
*
она расширится до всех файлов в текущей папке. Поэтому используйте его только в том случае, если в вашем файле нет такого сценария.источник
IFS
только временно (чтобы оно восстанавливало свое исходное значение после этой команды), сохраняя при этом присвоениеarr
?IFS=$'\n' arr=($(echo 'a 1'; echo '*'; echo 'b 2')); printf "%s\n" "${arr[@]}"
IFS=... command
не изменяетсяIFS
в текущей оболочке. ОднакоIFS=... other_variable=...
(без какой-либо команды) изменяется как в текущей оболочке, такIFS
иother_variable
в ней.arr=
обозначения (по сравнению сmapfile
/readarray
).Вы можете просто прочитать каждую строку из файла и назначить ее массиву.
#!/bin/bash i=0 while read line do arr[$i]="$line" i=$((i+1)) done < file.txt
источник
Используйте mapfile или прочтите -a
Всегда проверяйте свой код с помощью shellcheck . Часто он дает правильный ответ. В этом случае SC2207 охватывает чтение файла, который содержит значения, разделенные пробелом или новой строкой, в массив.
Не делай этого
Файлы со значениями, разделенными символами новой строки
mapfile -t array < <(mycommand)
Файлы со значениями, разделенными пробелами
IFS=" " read -r -a array <<< "$(mycommand)"
Страница проверки оболочки даст вам объяснение, почему это считается лучшей практикой.
источник
В этом ответе говорится использовать
mapfile -t myArray < file.txt
Я сделал прокладку на случай,
mapfile
если выmapfile
по какой-то причине хотите использовать на bash <4.x. Он использует существующуюmapfile
команду, если вы используете bash> = 4.xНа данный момент только варианты
-d
и-t
работают. Но этого должно быть достаточно для приведенной выше команды. Я тестировал только на macOS. В macOS Sierra 10.12.6 используется системный bash3.2.57(1)-release
. Так что прокладка может пригодиться. Вы также можете просто обновить свой bash с помощью homebrew, собрать bash самостоятельно и т. Д.Он использует этот метод для установки переменных в один стек вызовов.
источник