GNU/Linux >> Znalost Linux >  >> Ubuntu

Jak příkaz (tj. Grep) ví, kdy je spuštěn v rámci globálního rozšíření?

Podle mého chápání je zástupný znak glob interpretován shellem, který pak spustí daný příkaz pro každý odpovídající název souboru. Předpokládejme, že mám soubory:abc1, abc2, and abc3 v mém aktuálním adresáři. Pak například echo abc* bude opakovat jednou pro každý soubor začínající na „abc“.

Pokud však spustím grep 'foo' abc* , Myslím, že by to mělo běžet:

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

Což znamená, že bych měl dostat následující výstup (za předpokladu, že všechny soubory obsahují jeden řádek s nápisem „foo“):

foo
foo
foo

Místo toho však dostávám:

abc1:foo
abc2:foo
abc3:foo

Takže si myslím, že pro to existují 2 možná vysvětlení. Za prvé, grep nějakým způsobem dokáže detekovat, že byl použit s výrazy glob a odpoví odesláním názvů souborů před shodami. Za druhé, protože můžete do grepu předat více souborů, shell ve skutečnosti spustí pouze 1 příkaz:

grep 'foo' abc1 abc2 abc3

To však funguje pouze proto, že grep na konci přijímá více souborů. Je možné, že jiný příkaz by umožnil předat pouze 1 soubor. Pokud byste tedy chtěli spustit příkaz pro více souborů odpovídajících globu, nefungovalo by to, kdyby globbing fungoval pomocí druhé metody popsané výše.

Každopádně, může to někdo osvětlit?

Díky!

Přijatá odpověď:

V tom je trik:příkaz neví, práci dělá shell

Vezměme si například grep 'abc' *.txt . Pokud spustíme sledování systémových volání, uvidíte něco takového:

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 +++

Shell expandoval *.txt do všech názvů souborů v aktuálním adresáři, které končí .txt rozšíření. Váš shell tak efektivně překládá grep 'abc' *.txt do grep 'abc' file1.txt file2.txt file3.txt . . . . Váš druhý předpoklad je tedy správný.

První předpoklad není správný – programy nemají způsob, jak detekovat glob. Je možné předat * jako řetězcový argument příkazu, ale je na příkazu, aby rozhodl, co s tím potom udělá. Rozšíření názvu souboru je však vlastnictvím vašeho příslušného shellu, jak jsem již zmínil.

To však funguje pouze proto, že grep na konci přijímá více souborů. Je možné, že jiný příkaz by umožnil předání pouze 1 souboru.

Naprosto správně ! Programy neomezují počet přijatelných argumentů příkazového řádku (například v C je to pole řetězců const char *args[] a v pythonu sys.argv[] ), ale dokážou zjistit délku tohoto pole nebo zda něco neočekávaného není v nesprávné poloze pole. grep nedělá to a přijímá více souborů, což je záměrné.

Související:Po upgradu na Ubuntu 13.10 Firefox někdy zhroutí počítač?

Na okraj, nesprávné citování spojené s globbingem s grep může být někdy problém. Zvažte toto:

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 +++

Nepřipravený uživatel by očekával, že grep bude odpovídat libovolnému řádku s est písmena v něm pocházela z roury, ale místo toho expanze názvu shellu vše zkroutila. Viděl jsem to často u lidí, kteří dělají ps aux | grep shell_script_name.sh a očekávají, že najdou jejich proces spuštěný, ale protože spustili příkaz ze stejného adresáře, kde byl skript , rozšíření názvu souboru shellu vytvořilo grep příkaz vypadat v zákulisí úplně jinak, než jak uživatel očekával.

Správným způsobem by bylo použití jednoduchých uvozovek:

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

Ubuntu
  1. Jak používat Linuxový příkaz grep

  2. Jak spustíme příkaz uložený v proměnné?

  3. Jak spustit příkaz, když se aktualizuje obsah adresáře?

  1. Jak funguje Tee Command?

  2. Jak příkaz Xdg-open ví, kterou aplikaci použít k otevření souboru?

  3. Jak spustit původní příkaz s aliasem se stejným názvem?

  1. Jak skrýt výstup terminálu při provádění příkazu?

  2. Jak spustit aplikaci po nastavenou dobu v prostředí Shell?

  3. Jak zjistím, zda je nutné spustit systemctl daemon-reload