GNU/Linux >> Znalost Linux >  >> Linux

Jak se Linux vypořádává se skripty shellu?

Pokud použijete strace můžete vidět, jak je skript shellu spuštěn, když je spuštěn.

Příklad

Řekněme, že mám tento skript shellu.

$ cat hello_ul.bash 
#!/bin/bash

echo "Hello Unix & Linux!"

Spusťte jej pomocí strace :

$ strace -s 2000 -o strace.log ./hello_ul.bash
Hello Unix & Linux!
$

Podívejte se do strace.log soubor odhaluje následující.

...
open("./hello_ul.bash", O_RDONLY)       = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, 0x7fff0b6e3330) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR)                   = 0
read(3, "#!/bin/bash\n\necho \"Hello Unix & Linux!\"\n", 80) = 40
lseek(3, 0, SEEK_SET)                   = 0
getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=4*1024}) = 0
fcntl(255, F_GETFD)                     = -1 EBADF (Bad file descriptor)
dup2(3, 255)                            = 255
close(3)     
...

Jakmile je soubor načten, je pak spuštěn:

...
read(255, "#!/bin/bash\n\necho \"Hello Unix & Linux!\"\n", 40) = 40
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc0b38ba000
write(1, "Hello Unix & Linux!\n", 20)   = 20
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
read(255, "", 40)                       = 0
exit_group(0)                           = ?

Ve výše uvedeném můžeme jasně vidět, že celý skript se zdá být načten jako jedna entita a poté spuštěn. Takže by se to "objevilo" alespoň v případě Bash, že načte soubor a pak jej spustí. Takže si myslíte, že byste mohli skript upravovat, když běží?

POZNÁMKA: Ale ne! Čtěte dále, abyste pochopili, proč byste si neměli zahrávat se spuštěným souborem skriptu.

A co ostatní tlumočníci?

Ale vaše otázka je trochu mimo. Není to Linux, kdo nutně načítá obsah souboru, je to interpret, který načítá obsah, takže je opravdu na tom, jak je interpret implementován, zda načte soubor celý nebo po blocích či řádcích.

Proč tedy nemůžeme soubor upravit?

Pokud však používáte mnohem větší skript, všimnete si, že výše uvedený test je trochu zavádějící. Ve skutečnosti většina interpretů načítá své soubory v blocích. To je docela standardní u mnoha unixových nástrojů, kde načtou bloky souboru, zpracují jej a poté načtou další blok. Toto chování můžete vidět v této otázce a odpovědi, kterou jsem před chvílí napsal ohledně grep , s názvem:Kolik textu pokaždé spotřebuje grep/egrep?.

Příklad

Řekněme, že vytvoříme následující skript shellu.

$ ( 
    echo '#!/bin/bash'; 
    for i in {1..100000}; do printf "%s\n" "echo \"$i\""; done 
  ) > ascript.bash;
$ chmod +x ascript.bash

Výsledkem je tento soubor:

$ ll ascript.bash 
-rwxrwxr-x. 1 saml saml 1288907 Mar 23 18:59 ascript.bash

Který obsahuje následující typ obsahu:

$ head -3 ascript.bash ; echo "..."; tail -3 ascript.bash 
#!/bin/bash
echo "1"
echo "2"
...
echo "99998"
echo "99999"
echo "100000"

Nyní, když to spustíte pomocí stejné techniky výše s strace :

$ strace -s 2000 -o strace_ascript.log ./ascript.bash
...    
read(255, "#!/bin/bash\necho \"1\"\necho \"2\"\necho \"3\"\necho \"4\"\necho \"5\"\necho \"6\"\necho \"7\"\necho \"8\"\necho \"9\"\necho \"10\"\necho 
...
...
\"181\"\necho \"182\"\necho \"183\"\necho \"184\"\necho \"185\"\necho \"186\"\necho \"187\"\necho \"188\"\necho \"189\"\necho \"190\"\necho \""..., 8192) = 8192

Všimnete si, že soubor je načítán v krocích po 8 kB, takže Bash a další shelly pravděpodobně nenačtou soubor celý, spíše je načtou po blocích.

Odkazy

  • Číslo #! magie, podrobnosti o mechanismu shebang/hash-bang v různých příchutích Unix

Toto je více závislé na prostředí než na OS.

V závislosti na verzi ksh číst skript na vyžádání po bloku 8 kB nebo 64 kB.

bash přečtěte si skript řádek po řádku. Vzhledem k tomu, že řádky faktů mohou mít libovolnou délku, přečte pokaždé 8176 bajtů od začátku dalšího řádku k analýze.

Toto je pro jednoduché konstrukce, tj. sadu jednoduchých příkazů.

Pokud se používají příkazy strukturované v shellu (případ, který nepřijímaná odpověď nezvažuje ) jako for/do/done smyčka, case/esac přepínač, dokument here, subshell uzavřený v závorkách, definice funkce atd. a libovolnou kombinaci výše uvedených, interprety shellu čte až do konce konstrukce, aby se nejprve ujistil, že nedochází k chybě syntaxe.

To je poněkud neefektivní, protože stejný kód lze číst znovu a znovu mnohokrát, ale zmírňuje to skutečnost, že se tento obsah běžně ukládá do mezipaměti.

Bez ohledu na interpretaci shellu je velmi nerozumné upravovat skript shellu během jeho provádění, protože shell může znovu číst jakoukoli část skriptu a to může vést k neočekávaným syntaktickým chybám, pokud nejsou synchronizovány.

Všimněte si také, že bash může selhat s porušením segmentace, když není schopen uložit příliš velkou konstrukci skriptu, kterou ksh93 dokáže číst bezchybně.


To závisí na tom, jak funguje interpret spouštějící skript. Vše, co jádro udělá, je všimnout si, že soubor, který se má spustit, začíná #! , v podstatě spustí zbytek řádku jako program a dá mu spustitelný soubor jako argument. Pokud tam uvedený tlumočník čte tento soubor řádek po řádku (jako to dělají interaktivní shelly s tím, co napíšete), je to to, co dostanete (ale víceřádkové smyčkové struktury se čtou a uchovávají pro opakování); pokud interpret uschová soubor do paměti, zpracuje jej (možná jej zkompiluje do přechodné reprezentace, jako to dělají Perl a Pyton), soubor se před spuštěním přečte celý.

Pokud soubor mezitím smažete, soubor se nesmaže, dokud jej interpret nezavře (jako vždy soubory zmizí, když zmizí poslední odkaz, ať už jde o záznam v adresáři nebo proces, který jej udržuje otevřený).


Linux
  1. Linux – Jak funguje průměrná zátěž u moderních procesorů?

  2. Jak analyzovat Json pomocí skriptování Shell v Linuxu?

  3. Jak přejmenuji soubory s mezerami pomocí prostředí Linux?

  1. Jak používám Vagrant s libvirt

  2. Jak šifrovat soubory pomocí gocryptfs na Linuxu

  3. Základy Linuxu:Jak stahovat soubory do prostředí pomocí Wget

  1. Jak změnit Shell v Linuxu

  2. Jak změnit slovo v souboru pomocí skriptu linux shell

  3. Jak mohu provést rozdělení s proměnnými v prostředí Linuxu?