Почему команда cat не использует свою командную среду? [дубликат]

-1
13.03.2018, 00:11
3 ответа

Потому что во втором примере $fрасширяется вашей оболочкой, а не cat. Предполагая, что fне установлено иначе в среде вашей оболочки, $fрасширяется до пустой строки, а catзатем читается со стандартного ввода, как если бы не было аргументов.

В вашем первом примере $fнаходится внутри одинарных кавычек, поэтому он не расширяется исходной оболочкой, но расширяется экземпляром sh, который видитcat "$f"и имеет набор fв своей среде.

0
28.01.2020, 05:06

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

Вы можете увидеть это более наглядно с помощью

$ f=1
$ f=2 echo $f
1
$

Команда echoвыполнялась в среде, в которой для параметра fбыло установлено значение 2, но назначения выполнялись в среде команды (под -конструкция ), а не в среде оболочки, используемой для построения команда.

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

2
28.01.2020, 05:06

Резюме

Команда f=test.txt sh -c 'cat "$f"'производит выходные данные, потому что назначение переменной f=test.txtпроисходит до раскрытия (одиночного -цитируемого )аргумента команды -'cat "$f"'. Одинарные кавычки -предотвращают расширение до тех пор, пока не будет выполнена подкоманда cat "$f".

Команда f=test.txt cat $fне производит а не вывод, потому что назначение переменной f=test.txtпроисходит после раскрытия (без кавычек )аргумента команды -$f.

Почему f=test.txt cat $fничего не выводит

Сначала я попытаюсь объяснить, почему команда f=test.txt cat $fне выводит никаких результатов, несмотря на ваши ожидания. Здесь может быть некоторая путаница в порядке оценки в так называемой простой команде .

Возможно, вы предположили, что присваивание переменной в прологе команды (, т. е. присваивание f=test.txt), происходит до расширения переменной в теле команды (, т. е. раскрытия $fв cat $f). Но на самом деле это не так. Чтобы убедиться в этом, мы можем обратиться к странице, посвященной расширению простых команд в Руководстве Bash, или к подразделу о простых командах в Спецификации Posix . Обе эти ссылки включают следующий отрывок:

A "simple command" is a sequence of optional variable assignments and redirections, in any sequence, optionally followed by words and redirections, terminated by a control operator.

When a given simple command is required to be executed (that is, when any conditional construct such as an AND-OR list or a case statement has not bypassed the simple command), the following expansions, assignments, and redirections shall all be performed from the beginning of the command text to the end:

  1. The words that are recognized as variable assignments or redirections according to Shell Grammar Rules are saved for processing in steps 3 and 4.

  2. The words that are not variable assignments or redirections shall be expanded. If any fields remain following their expansion, the first field shall be considered the command name and remaining fields are the arguments for the command.

  3. Redirections shall be performed as described in Redirection.

  4. Each variable assignment shall be expanded for tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal prior to assigning the value.

Обратите внимание, что на шаге 2 происходит расширение переменной в команде, но шаг 1 сообщает нам, что назначения переменных сохраняются до шагов 3 и 4. Отсюда следует, что выражение cat $fрасширяется доcat(без аргументы )до выполнения присваивания f=test.txt. Это объясняет, почему вы не получаете никакого вывода.

Дальнейшее обсуждение этой темы см. в следующих сообщениях:

Почемуf=test.txt sh -c 'cat "$f"'производит вывод

Далее я попытаюсь объяснить, почему командаf=test.txt sh -c 'cat "$f"'производит вывод. Для этого нам нужно просмотреть полный список общих операций, выполняемых оболочкой :

.
  1. The shell reads its input from a file (see sh), from the -c option or from the system() and popen() functions defined in the System Interfaces volume of POSIX.1-2008. If the first line of a file of shell commands starts with the characters "#!", the results are unspecified.

  2. The shell breaks the input into tokens: words and operators; see Token Recognition.

  3. The shell parses the input into simple commands (see Simple Commands) and compound commands (see Compound Commands).

  4. The shell performs various expansions (separately) on different parts of each command, resulting in a list of pathnames and fields to be treated as a command and arguments; see wordexp.

  5. The shell performs redirection (see Redirection) and removes redirection operators and their operands from the parameter list.

  6. The shell executes a function (see Function Definition Command), built-in (see Special Built-In Utilities), executable file, or script, giving the names of the arguments as positional parameters numbered 1 to n, and the name of the command (or in the case of a function within a script, the name of the script) as the positional parameter numbered 0 (see Command Search and Execution).

  7. The shell optionally waits for the command to complete and collects the exit status (see Exit Status for Commands).

Здесь вы можете видеть, что вызов функции/встроенной -в/исполняемом/скрипте (шаг 6 в этом списке )происходит после синтаксического анализа простой команды. Следовательно, назначение f=test.txtпроисходит до выполнения программы sh -c 'cat "$f"'. А поскольку аргумент заключен в одинарные кавычки -, он анализируется только после выполнения команды. Поэтому подкоманда расширяется до cat "test.txt".

6
28.01.2020, 05:06

Теги

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