читать -a массив -d '\ n' <foo, код выхода 1


8

Если я попытаюсь выполнить

read -a fooArr -d '\n' < bar

код выхода равен 1 - хотя он выполняет то, что я хочу; поместите каждую строку barв элемент массива fooArr(используя bash 4.2.37).

Может кто-нибудь объяснить, почему это происходит


Я нашел другие способы решения этой проблемы, например, приведенные ниже, так что я не об этом.

for ((i=1;; i++)); do
    read "fooArr$i" || break;
done < bar

или

mapfile -t fooArr < bar

Ответы:


14

Необходимо пояснить, что команда работала, а не код выхода

'\n'это два символа: обратный слеш \и буква n. То, что вы думали, что вам нужно было $'\n', это перевод строки (но это тоже было бы неправильно, см. Ниже).

-dВариант делает это:

  -d delim  continue until the first character of DELIM is read, rather
            than newline

Таким образом, без этой опции, readбудет читать до новой строки, разделить строку на слова, используя символы в $IFSкачестве разделителей, и поместить слова в массив. Если вы укажете -d $'\n', устанавливая разделитель строки на новую строку, это будет делать то же самое . Установка -d '\n'означает, что он будет читать до первого обратного слеша (но, опять же, см. Ниже), который является первым символом в delim. Поскольку в вашем файле отсутствует обратная косая черта, в readконце файла оно заканчивается и:

Exit Status:
The return code is zero, unless end-of-file is encountered, read times out,
or an invalid file descriptor is supplied as the argument to -u.

Вот почему код выхода равен 1.

Исходя из того, что вы считаете, что команда сработала, мы можем сделать вывод, что в файле нет пробелов, поэтому readпосле прочтения всего файла в тщетной надежде найти обратную косую черту разделит его на пробелы (значение по умолчанию: $IFS), включая переводы строк. Таким образом, каждая строка (или каждое слово, если строка содержит более одного слова) помещается в массив.

Загадочный случай с прорезной обратной косой чертой

Теперь, как я узнал, что файл не содержит обратной косой черты? Потому что вы не поставили -rфлаг read:

  -r                do not allow backslashes to escape any characters

Таким образом, если бы у вас были какие-либо обратные слеши в файле, они были бы удалены, если бы у вас не было двух из них подряд. И, конечно же, есть свидетельства, readу которых был код выхода 1, который показывает, что он не нашел обратной косой черты, поэтому не было и двух из них подряд.

Takeaways

Bash не был бы bash, если бы не каждая команда скрывалась за каждой командой, и не readявляется исключением. Вот пара:

  1. Если вы не укажете -r, readбудет интерпретировать escape-последовательности обратной косой черты. Если это не то, что вы на самом деле хотите (что иногда и происходит, но только изредка), не забывайте указывать, -rчтобы не допустить исчезновения символов в редком случае обратной косой черты на входе.

  2. Тот факт, что readвозвращается код выхода 1, не означает, что это не удалось. Это вполне могло бы быть успешным, за исключением поиска конца строки. Так что будьте осторожны с таким циклом: while read -r LINE; do something with LINE; done потому что он не сможет работать do somethingс последней строкой в ​​редком случае, когда последняя строка не имеет символа новой строки в конце.

  3. read -r LINE сохраняет обратную косую черту, но не сохраняет начальные или конечные пробелы.


Спасибо! Я думал, что попробовал подход $ '\ n', но не думаю: / хотя приятно знать о -r
RasmusWL

2
«тот редкий случай, когда в последней строке не было новой строки», не кажется мне веской причиной советовать «никогда не использовать while read». В противном случае, фантастический ответ.
Гленн Джекман

@glennjackman: Вы можете использовать, while readесли у вас ничего нет внутри цикла. Иначе это ошибка, ждущая, чтобы укусить тебя - и поверь мне, я был укушен.
Ричи

2
Последняя строка всегда имеет новую строку. Вот как определяется строка: она заканчивается новой строкой. Если непустой файл не заканчивается новой строкой, это не текстовый файл, и вы не можете использовать инструменты обработки текста, такие как утилита оболочки read.
Жиль "ТАК - перестань быть злым"

2
@glennjackman: Я перебираю колоночные файлы с помощью awk, в основном. Для перебора целых строк, где файл не слишком большой, mapfileэто довольно круто. Для быстрого и грязного взлома я буду использовать запрещенный цикл while, но я перестал вставлять это в производственные скрипты. YMMV и я смягчили предупреждение в ответе.
Ричи

4

Это ожидаемое поведение:

Код возврата равен нулю, если не встречается конец файла, [...]

start cmd:> echo a b c | { read -a testarray; echo $?; }
0

start cmd:> echo -n a b c | { read -a testarray; echo $?; }
1
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.