Si vous utilisez, strace
vous pouvez voir comment un script shell est exécuté lors de son exécution.
Exemple
Disons que j'ai ce script shell.
$ cat hello_ul.bash
#!/bin/bash
echo "Hello Unix & Linux!"
L'exécuter en utilisant strace
:
$ strace -s 2000 -o strace.log ./hello_ul.bash
Hello Unix & Linux!
$
Un coup d'œil à l'intérieur du strace.log
fichier révèle ce qui suit.
...
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)
...
Une fois le fichier lu, il est alors exécuté:
...
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) = ?
Dans ce qui précède, nous pouvons clairement voir que l'intégralité du script semble être lu comme une seule entité, puis exécuté par la suite. Il semblerait donc "apparaître" au moins dans le cas de Bash qu'il lit le fichier, puis l'exécute. Vous pensez donc que vous pouvez modifier le script pendant son exécution?
REMARQUE: non! Lisez la suite pour comprendre pourquoi vous ne devriez pas jouer avec un fichier de script en cours d'exécution.
Et les autres interprètes?
Mais votre question est légèrement décalée. Ce n'est pas Linux qui charge nécessairement le contenu du fichier, c'est l'interpréteur qui charge le contenu, donc c'est vraiment à la façon dont l'interprète l'implémente, qu'il charge le fichier entièrement ou en blocs ou en lignes à la fois.
Alors pourquoi ne pouvons-nous pas modifier le fichier?
Si vous utilisez un script beaucoup plus volumineux, vous remarquerez cependant que le test ci-dessus est un peu trompeur. En fait, la plupart des interprètes chargent leurs fichiers en blocs. C'est assez standard avec de nombreux outils Unix où ils chargent des blocs d'un fichier, le traitent, puis chargent un autre bloc. Vous pouvez voir ce comportement avec cette Q&R U&L que j'ai rédigée il y a quelque temps concernant grep
: Combien de texte grep / egrep consomme-t-il à chaque fois? .
Exemple
Disons que nous faisons le script shell suivant.
$ (
echo '#!/bin/bash';
for i in {1..100000}; do printf "%s\n" "echo \"$i\""; done
) > ascript.bash;
$ chmod +x ascript.bash
Résultat dans ce fichier:
$ ll ascript.bash
-rwxrwxr-x. 1 saml saml 1288907 Mar 23 18:59 ascript.bash
Qui contient le type de contenu suivant:
$ head -3 ascript.bash ; echo "..."; tail -3 ascript.bash
#!/bin/bash
echo "1"
echo "2"
...
echo "99998"
echo "99999"
echo "100000"
Maintenant, lorsque vous exécutez cela en utilisant la même technique ci-dessus avec 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
Vous remarquerez que le fichier est lu par incréments de 8 Ko, donc Bash et les autres shells ne chargeront probablement pas un fichier dans son intégralité, ils les lisent plutôt par blocs.
Les références