Завершающие символы новой строки и встроенная функция чтения bash

В bash это работает:

echo -n $'a\nb\nc\n' | while read x; do echo = $x =; done

В то время как циклы через три раза

= a =
= b =
= c =

Но представьте себе текстовый файл, в котором нет обычного завершающего символа новой строки. Я думаю, что read все еще должно работать для всех трех строк, но это не так. Я просто получаю:

echo -n $'a\nb\nc' | while read x; do echo = $x =; done

= a =
= b =

help read в bash на самом деле не проясняет.

Примечание. Мне не нужно решать эту проблему, и я вижу несколько способов исправить это самостоятельно. Мне любопытно, и у меня возникает соблазн подать отчет об ошибке - обычно я стараюсь уважать файлы, которые могут не иметь завершающей новой строки. Я столкнулся с этим при использовании опции -d для чтения. read -d " " будет разделяться на пробелы вместо новых строк, но будет пропущена последняя запись, если у нее нет завершающего пробела.

(Ubuntu. GNU bash, версия 4.1.5(1)-выпуск)


person Aaron McDaid    schedule 22.12.2011    source источник
comment
для чего это стоит, ваш 2-й скрипт работает как первый с ksh. Удачи.   -  person shellter    schedule 23.12.2011
comment
Я только что проверил: ksh ведет себя так же, как bash в данном случае, @shellter.   -  person codeforester    schedule 12.01.2021
comment
@codeforester: я уверен, что проверил это перед публикацией, но у меня больше нет доступа к UWIN ksh93. Также возможно, что версия, которую я использовал, отличается от версии, которую используете вы, хотя я почти уверен, что видел эту проблему в группах электронной почты UWIN/ksh (~‹10 лет назад ;-)). Мне нравится ваш вариант ниже. Ваше здоровье.   -  person shellter    schedule 12.01.2021


Ответы (2)


$ man bash
   read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
          One line is read from the standard input, ...

Я думаю, что ключ: How to define "One line".
Делает ли text without a '\n' at the end One line?
Думаю, read так не думаю.

person kev    schedule 22.12.2011
comment
Мой текстовый редактор думает, что это строка, и я думаю, что каждый текстовый редактор так и сделает. Так что, если текстовый редактор может разумно работать с файлами, в которых нет новой строки в качестве самого последнего символа, то я думаю, что read тоже должен :-) - person Aaron McDaid; 22.12.2011

Если вы хотите, чтобы приведенный выше цикл обрабатывал неполную строку, сделайте следующее:

echo -n $'a\nb\nc' | while read x || [[ $x ]]; do echo = $x =; done

который дает:

= a =
= b =
= c =

Когда read встречает неполную строку, она считывает ее в переменную (в данном случае x), но возвращает ненулевой код выхода, который завершит цикл, а || [[ $x ]] также позаботится о запуске цикла для неполной строки. Когда read вызывается в следующий раз, считывать нечего, и он завершается с 1, также устанавливая x в пустую строку, что гарантирует завершение цикла.


Связанный

person codeforester    schedule 12.01.2021