Почему чтение выдает ошибку в bash, но работает нормально?

Этот сценарий bash записывает массив в файл, а затем считывает файл обратно в другой массив. (Это полезно для обмена данными между сценариями на основе массивов.) Однако странная ошибка, о которой не сообщается, перехватывается строкой IFS (строка 12). Почему?

#!/bin/bash

# eso-error-ic

trap 'echo Error trapped, with code $?, on line ${LINENO}' ERR

# write data to a file
arr=(0 abc) && printf "%s\n" "${arr[@]}" > eso.out

# read data from the file into an array
# throws an error!!
IFS=$'\n' read -d '' -a new_arr < eso.out

# but it worked...
echo ${new_arr[0]}
echo ${new_arr[1]}

Вывод скрипта:

Error trapped, with code 1, on line 12
0
abc

Чего не хватает, так это какого-либо сообщения, отображаемого при возникновении ошибки. Все, что вы получаете, это сообщение от ловушки, но не сообщение о что ошибка является.

Другими словами, строка IFS/read выдает ошибку, которая перехватывается, но сообщение об ошибке не отображается, и строка правильно считывает файл в переменную массива. Он работает, не сообщает об ошибке, но ловится «ошибка».

Если вы закомментируете строку ловушки ИЛИ переключитесь на подход command/eval/cat для чтения файла в массив (как было предложено здесь), ошибка не фиксируется. Вот как будет выглядеть строка command/eval/cat для этого скрипта (заменяет строку 12):

IFS=$'\n' GLOBIGNORE='*' command eval 'new_arr=($(cat eso.out))'

person DarkerIvy    schedule 15.02.2018    source источник
comment
Я могу воспроизвести Bash 3.2.57(1) на MacOS High Sierra с помощью простого read -d '' variable <<<"moo"; echo $?   -  person tripleee    schedule 15.02.2018
comment
Вот это да. Гораздо проще репо! Я воспроизвел его на Bash 4 на CentOS 6/7, RHEL 6/7 и Bash 3 и 4 на Apple Darwin 17.3 (High Sierra).   -  person DarkerIvy    schedule 15.02.2018
comment
Дублирование кросс-сайта с подробным объяснением: unix.stackexchange.com/questions/80045/   -  person Aserre    schedule 15.02.2018
comment
Кстати, ловушки set -e и/или ERR обычно считаются плохой идеей. См. BashFAQ #105, пропуская аллегорию для упражнений ниже, если вы спешите; или список несовместимостей между реализациями set -e в разных оболочках (и, соответственно, степень непредсказуемости его поведения) здесь.   -  person Charles Duffy    schedule 15.02.2018
comment
Связанный вопрос (идентичная причина) на этом сайте: Почему UNIX во время читать не читать последнюю строку?   -  person Charles Duffy    schedule 15.02.2018
comment
Кстати, в общем, я бы предложил readarray -t new_arr <eso.dat (если вам не нужна совместимость с bash до 4.x) -- за исключением случаев, когда вы читаете из подстановки процесса вместо файла, таким образом, переход от успеха или неудачи этого процесса к успеху read путем добавления завершающего или NUL или нет, является активно полезной возможностью.   -  person Charles Duffy    schedule 15.02.2018
comment
@CharlesDuffy проблема с readarray в том, что он недоступен на bash 4.4 на Apple, платформе, на которой я обычно тестирую перед переходом на сервер. Почему? Без понятия.   -  person DarkerIvy    schedule 15.02.2018
comment
@DarkerIvy, он абсолютно доступен с MacPorts или сборками Homebrew для bash 4.4 на MacOS; Я использую его там все время. Я подозреваю, что вместо этого ваш сценарий интерпретируется bash 3.2, поставляемым Apple, и предлагаю запустить echo $BASH_VERSION в том же контексте интерпретатора оболочки, который генерирует любое сообщение о readarray недоступности.   -  person Charles Duffy    schedule 15.02.2018
comment
@CharlesDuffy еще раз, вы абсолютно правы. shebang и profile указывают на две разные версии. Он доступен.   -  person DarkerIvy    schedule 15.02.2018


Ответы (1)


Ошибка возникает из-за того, что не получен разделитель, который ожидал read. я получаю то же самое с

read -d x variable <<<"hello"

Если я изменю ввод на "hellox", ошибка исчезнет.

Как упоминал @Aserre, подробный анализ находится на нашем Unix & Дочерний сайт Linux, и, как указал @CharlesDuffy, общий обходной путь:

read variable || [[ $variable ]]

который используется даже без -d для работы с файлами, в которых может отсутствовать завершающий символ новой строки.

person tripleee    schedule 15.02.2018
comment
Вы можете убрать неопределенность из этого ответа. Это точно, и именно поэтому read x || [[ $x ]] является идиомой, когда желательно допускать отсутствующий разделитель. - person Charles Duffy; 15.02.2018
comment
@tripleee Спасибо за объяснение. Я все еще говорю, что это ошибка ошибки, чтобы выйти из 1 без stderr-ing чего-либо. - person DarkerIvy; 15.02.2018