Почему эхо-бар отличается от эхо-бара?

10

сравнить

echo -n "bar"

с

echo "bar" -n

Первый делает то, что, как я думаю, должен делать (печатает «бар» без новой строки), а второй - нет. Это ошибка или по замыслу? Почему он отличается от многих программ Cli в том, что вы не можете перемещать опции? Например, tail -f /var/log/messagesэто точно так же, как tail /var/log/messages -f. Я иногда делаю последнее, когда забываю, что хотел первое, потому что внутренне параметры и аргументы переставляются, обычно с помощью getopt .

Обновление: да, я изначально не ответил на мой вопрос. Я убрал нерфа, вам придется просматривать историю, чтобы некоторые ответы имели смысл.

xenoterracide
источник
3
Из того, что я вижу, разница есть сразу. echo -n "bar"дает "бар", в то время как echo "bar" -nдает "бар-н"
phunehehe

Ответы:

18

Как заметили большинство других, «-n» интерпретируется буквально, если размещено где-нибудь, но сразу после echoкоманды.

Исторически UNIX-утилиты были такими: они искали параметры только сразу после имени команды. Вероятно, либо BSD, либо GNU стали первыми в более гибком стиле (хотя я могу ошибаться), так как даже сейчас POSIX указывает старый способ как правильный (см. Рекомендацию 9, а также man 3 getoptв системе Linux). В любом случае, хотя большинство утилит Linux в наши дни используют новый стиль, есть некоторые несогласные echo.

EchoЭто беспорядок, связанный со стандартами, поскольку к моменту появления POSIX в игре было по крайней мере две принципиально противоречивые версии . С одной стороны, у вас есть стиль SYSV, который интерпретирует символы с обратной косой чертой, но в остальном обрабатывает свои аргументы буквально, не принимая никаких опций. С другой стороны, у вас есть BSD-стиль, который рассматривает инициал -nкак особый случай и выводит буквально все остальное. А поскольку echoэто так удобно, у вас есть тысячи сценариев оболочки, которые зависят от того или иного поведения:

echo Usage: my_awesome_script '[-a]' '[-b]' '[-c]' '[-n]'
echo -a does a thing.
echo -b does something else.
echo -c makes sure -a works right.
echo -- DON\'T USE -n -- it\'s not finished! --

Из-за семантики «относиться ко всему буквально» невозможно даже добавить новую опцию, echoне ломая вещи. Если бы GNU использовала гибкую схему опций, ад был бы свободен.

Кстати, для лучшей совместимости между реализациями оболочки Bourne используйте printfвместоecho .

ОБНОВЛЕНО, чтобы объяснить, почему, echoв частности, не используются гибкие параметры.

Jander
источник
upvote, так как вы единственный, кто упомянул об ожидаемом поведении getopt.
Джеффри Бачелет
@jander, почему эхо является "несогласным"? Я думаю, что это GNU Coreutil?
ксенотеррацид
@xeno: я обновил свой ответ. По сути, GNU не хотел ломать вещи.
Jander
1
Принимая варианты после первого не-опции специфичен для GNU утилит и программ с использованием GNU Libc «s Getopt объектов. Пользователь всегда может получить обратно-совместимое поведение, установив переменную окружения POSIXLY_CORRECT.
Жиль "ТАК - перестань быть злым"
1
Для конкретного случая echoесть также реализации, которые распознают -eили -Eкак опции. Для переносимости, не начинайте с -или используйте что-то вроде printf %s -e.
Жиль "ТАК - перестань быть злым"
9

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

[11:07:44][dasonk@Chloe:~]: echo -n "bar"
bar[11:07:48][dasonk@Chloe:~]: echo "bar" -n
bar -n
Dason
источник
3
+1 точно. Если конвейер не выполняет то, что вы ожидаете, протестируйте каждую часть отдельно.
Микель
6

Вау, все объяснения длинны.

Это так просто:

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

Удалите, | md5sum и вы увидите, что результат отличается.

Mikel
источник
5

Из простого осмотра, это не ошибка по замыслу ...

echo "bar" -n | md5sum

a3f8efa5dd10e90aee0963052e3650a1

Попробуйте эту команду для себя:

echo "bar -n" | md5sum

Вы заметите, что в результате md5

a3f8efa5dd10e90aee0963052e3650a1

Вы просто перепутали использование -n в эхо.

В вашем первом примере кода

echo -n "bar" | md5sum

-n используется, чтобы сказать НЕ ставить новую строку после этого эха.

Ваш второй образец

echo "bar" -n | md5sum

трактует -n как буквальный текст.

icasimpan
источник