Bash/Python: команда `echo` вставляет новую строку, действуя как вход в другую команду?

У меня есть простой python script line_printer.py:

import fileinput
i = 1
for line in fileinput.input():
    print 'Line', str(i), ':', line.strip()
    i+=1

Я пытаюсь понять, как данные о трафике из команды echo на этот script влияют на результат по сравнению с чтением данных из файла.

Рассмотрим следующий вызов и вывод:

$ echo -e "chicken\ncow\npig"
chicken
cow
pig
$

Это для меня выглядит как echo добавило invisble \n после "g" в свиньи. Итак, как получилось, когда я звоню:

echo -e "chicken\ncow\npig" | python line_printer.py

Я получаю:

Line 1 : chicken
Line 2 : dog
Line 3 : cow

как вывод, а не:

Line 1 : chicken
Line 2 : dog
Line 3 : cow
Line 4 : 

Сначала я думал, что поведение модуля Python fileinput может состоять в том, чтобы отбросить окончательную строку в файле, если она пуста. Но когда я пытаюсь использовать содержимое файла some_lines.txt:

chicken
dog
cow
<blank line>

в качестве входа:

python line_printer.py some_lines.txt

Выход, который я получаю:

Line 1 : chicken
Line 2 : dog
Line 3 : cow
Line 4 : 

Итак, почему line_printer.py дает разные результаты на входе в зависимости от того, возникла ли она из stdin или из файла? Лучшее, что я могу сказать, как stdin (от echo), так и файл (от some_lines.txt) заканчиваются на \n, поэтому я либо ожидал, что вывод обоих включит Line 4 :, либо вывод не будет включите его.

Ответ 1

Эта команда ответит на ваш вопрос:

echo 'hi' | od -c

Причиной для возвращаемого символа \n является то, что stdout на терминале по умолчанию использует буферизацию строк - это означает, что он будет отображать только выходные данные, которые заканчиваются символом новой строки.

Играйте с командой printf:

printf "%s"  foo
printf "%s\n" anotherfoo

Ответ 2

Если вы посмотрите в источнике bash, bash -4.2/builtins/echo.def, вы увидите, что команда builtin echo всегда (строка 113) выводит окончательный \n (строка 194), если только был указан -n (строка 198), или вывод echo используется как строка (строка 166). Вы можете проверить это, выполнив

echo `echo "Ho ho ho"` | od -c

Вы увидите только один \n, потому что вывод echo "Ho ho ho" оценивается как строка в выражении echo `echo "Ho ho ho"`.

Он не имеет никакого отношения к настройке терминала.