Как делает команду (т.е. grep) знают, когда он выполняется как часть расширения шарика?

Согласно моему пониманию, подстановочный знак шарика интерпретируется оболочкой, которая затем выполняет данную команду для каждого имени файла соответствия. Предположим, что у меня есть файлы: abc1, abc2, and abc3 в моем текущем каталоге. Затем например, echo abc* отзовется эхом однажды для каждого имени файла, запускающегося с 'abc'.

Однако, если я работаю grep 'foo' abc*, Я предполагаю, что это должно работать:

grep 'foo' abc1
grep 'foo' abc2
grep 'foo' abc3

Что означает, что я должен получить следующий вывод (предполагающий, что все файлы содержат одну строку, которая говорит 'нечто'):

foo
foo
foo

Однако вместо этого я добираюсь:

abc1:foo
abc2:foo
abc3:foo

Таким образом, я полагаю, что существует 2 возможных объяснения этого. Во-первых, так или иначе grep, может обнаружить, что это использовалось с шариком выражения и отвечает путем вывода имен файлов перед соответствиями. Во-вторых, так как можно передать несколько файлов grep, оболочка на самом деле выполняет только 1 команду:

grep 'foo' abc1 abc2 abc3

Однако это только работает, потому что grep принимает несколько файлов в конце. Возможно, что другая команда только позволила бы 1 файлу быть переданным в. Таким образом, если бы Вы хотели выполнить команду для нескольких файлов, соответствующих шарику, то она не работала бы, если бы globbing работал с помощью второго метода, описанного выше.

Так или иначе кто-то может пролить некоторый свет на это?

Спасибо!

4
задан 18 March 2017 в 03:05

1 ответ

Это - прием: команда не знает, это - оболочка, которая делает задание

Рассмотрите, например, grep 'abc' *.txt. Если мы выполним трассировку системных вызовов, то Вы будете видеть что-то вроде этого:

bash-4.3$ strace -e trace=execve grep "abc" *.txt > /dev/null
execve("/bin/grep", ["grep", "abc", "ADDA_converters.txt", "after.txt", "altera_license.txt", "altera.txt", "ANALOG_DIGITAL_NOTES.txt", "androiddev.txt", "answer2.txt", "answer.txt", "ANSWER.txt", "ascii.txt", "askubuntu-profile.txt", "AskUbuntu_Translators.txt", "a.txt", "bash_result.txt", ...], [/* 80 vars */]) = 0
+++ exited with 0 +++

Оболочка расширена *.txt во все имена файлов в текущем каталоге тот конец с .txt расширение. Так эффективно Ваша оболочка переводит grep 'abc' *.txt команда в grep 'abc' file1.txt file2.txt file3.txt . . .. Таким образом Ваше второе предположение корректно.

Первое предположение не корректно - программы не имеют никакого способа обнаружить шарик. Возможно передать * как аргумент строки для управления но это - задание команды для решения, что сделать с ним затем. Расширение имени файла, однако, является свойством Вашей соответствующей оболочки, как я уже упомянул.

Однако это только работает, потому что grep принимает несколько файлов в конце. Возможно, что другая команда только позволила бы 1 файлу быть переданным в.

Точно правильный! Программы не ограничивают количество приемлемых параметров командной строки (например, в C это - массив строк const char *args[] и в Python sys.argv[] ), но они могут обнаружить длину того массива или является ли что-то неожиданное в неправильном положении массива. grep не делает этого и принимает несколько файлов, который является дизайном.


На ноте стороны неподходящее заключение в кавычки вместе с globbing с grep может иногда быть проблемой. Рассмотрите это:

bash-4.3$ echo "one two" | strace -e trace=execve grep *est*
execve("/bin/grep", ["grep", "self_test.sh", "test.wxg"], [/* 80 vars */]) = 0
+++ exited with 1 +++

Неприготовленный пользователь ожидал бы, что grep будет соответствовать любой строке est буквы в нем прибывающий из канала, но вместо этого расширения имени файла оболочки скрутили все вокруг. Я видел, что это происходит много с людьми, которые делают ps aux | grep shell_script_name.sh, и они ожидают находить свое выполнение процесса, но потому что они выполнили команду из того же каталога, где сценарий был, сделанное расширение имени файла оболочки grep управляйте для взгляда полностью отличающимися негласно от того, что ожидал пользователь.

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

bash-4.3$ echo "one two" | strace -e trace=execve grep '*est*'
execve("/bin/grep", ["grep", "*est*"], [/* 80 vars */]) = 0
+++ exited with 1 +++
5
ответ дан 1 December 2019 в 09:32

Другие вопросы по тегам:

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