Должен ли оболочку прочитать (скрипт) один символ за раз?

Ваша вещь heredoc намного проще написана, например:

print_status(){ paste -sd\\n /dev/null - /dev/null;}

print_status <<\doc
doc body
doc

Вам не нужно присваивать всему этому имя. Если уж на то пошло, то еще проще можно было бы написать так:

print_status(){ printf %s\\n '' "$@" '';}

print_status \
    'line 2' \
    'line 3' and lines 4,5,6

Я к тому, что, по-моему, это немного перебор - писать кучу текста в файл скрипта, который вы затем поручаете оболочке считать во временный файл (именно так обычно работают здесь-документы) и открывать этот временный файл на stdin какой-то команды, если ваша целевая команда просто предназначена для того, чтобы оболочка снова и снова считывала его обратно в переменную! Видите? Это немного избыточно, на мой взгляд.

3
08.01.2019, 13:25
2 ответа

Да для оболочки, совместимой с POSIX. Разработчик bash сказал следующее:

POSIX requires it for scripts that are read from stdin. When reading from a script given as an argument, bash reads blocks.

И действительно, спецификация POSIX говорит это (акцент мой):

When the shell is using standard input and it invokes a command that also uses standard input, the shell shall ensure that the standard input file pointer points directly after the command it has read when the command begins execution. It shall not read ahead in such a manner that any characters intended to be read by the invoked command are consumed by the shell (whether interpreted by the shell or not) or that characters that are not read by the invoked command are not seen by the shell.

То есть:(для скрипта stdin )оболочка должна читать один -символ -в --раз.

В локали C один символ равен одному байту.

Похоже, что posh, mksh, lksh, attsh, yash, ksh, zsh и bash соответствуют этому требованию.

Однако для ash (busybox sh )и dash это не так.

1
27.01.2020, 21:15

the shell will read from the script file or from a device descriptor

Или из конвейера, что, вероятно, является самым простым способом получить ввод fd без -поиска.

Should the shell also read one character at a time from its script input?.

Если он хочет поддерживать сценарии, запускающие команды, считывающие данные со стандартного ввода, и ожидающие получения ввода с использованием строк из самого сценария.

Как-то так:

$ cat foo.sh
#!/bin/sh
line | sed -e 's/^/* /'
xxx
echo "end."

$ cat foo.sh | bash
* xxx
end.

Команда lineчитает одну строку из стандартного ввода (строку xxx), а оболочка читает остальные строки как команды. Чтобы это работало, lineтакже нужно позаботиться о том, чтобы не читать ввод слишком далеко, иначе оболочка не увидит следующие строки. С утилитами GNU head -n1будет читаться слишком много, например. sed. Утилита lineиз util -linux заботится о том, чтобы читать по одному байту за раз, чтобы не читать дальше новой строки.

Приведенный выше скрипт не работает, например, с. dash, так как скрипт считывает полные блоки за раз:

$ cat foo.sh | dash
* 
dash: 3: xxx: not found
end.

Dash и Busybox читали полные блоки, другие, которые я тестировал, (Bash, Ksh, mkshи Zsh )считывали байт -на -байт.

Обратите внимание, что это довольно запутанный сценарий, и он не работает должным образом, если выполняется, например, как. bash foo.sh, так как в этом случае stdinне указывает на сам скрипт, и строка xxxвоспринималась бы как команда. Вероятно, было бы лучше использовать документ здесь -, если вы хотите включить данные в сам скрипт. Это работает с любой оболочкой, при запуске как sh bar.sh,sh < bar.shилиcat bar.sh | sh:

$ cat bar.sh
#!/bin/sh
sed -e 's/^/* /' <<EOF
xxx
EOF
echo "end."
4
27.01.2020, 21:15

Теги

Похожие вопросы