Voyons comment bash recherche les commandes en fonction de la variable d'environnement PATH.
yoichinakayama@penguin:~$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/yoichinakayama/.local/bin
yoichinakayama@penguin:~$ type hostname
hostname is /bin/hostname
yoichinakayama@penguin:~$ hostname
penguin
strace
yoichinakayama@penguin:~$ strace hostname 2>&1 |head -1
execve("/bin/hostname", ["hostname"], 0x7fe429adf0 /* 31 vars */) = 0
Et vous pouvez voir que / bin / hostname
est en cours d'exécution, mais vous ne pouvez voir que la trace d'où il a été exécuté, et vous ne pouvez pas le voir à la recherche d'une commande.
yoichinakayama@penguin:~$ bash -c "hostname"
penguin
Si vous démarrez bash puis que vous l'exécutez et que vous tracez le bash commencé, vous pouvez voir comment il recherche la commande.
yoichinakayama@penguin:~$ strace -f bash -c "hostname" 2>&1 |grep "\(execve\|fstatat\)"
...
newfstatat(AT_FDCWD, "/usr/local/bin/hostname", 0x7ff2d34128, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/bin/hostname", 0x7ff2d34128, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/bin/hostname", {st_mode=S_IFREG|0755, st_size=18440, ...}, 0) = 0
...
execve("/bin/hostname", ["hostname"], 0x31c1b008 /* 31 vars */) = 0
Selon la valeur de la variable d'environnement PATH [^ 1]
[^ 1]: La valeur était / usr / local / bin: / usr / bin: / bin: / usr / local / games: / usr / games: / home / yoichinakayama / .local / bin
Vous pouvez voir que vous exécutez ce que vous trouvez en recherchant dans l'ordre jusqu'à ce que vous le trouviez.
Si vous spécifiez une commande qui n'existe pas
yoichinakayama@penguin:~$ bash -c "hoge"
bash: hoge: command not found
Entraînera une erreur. dans ce cas
yoichinakayama@penguin:~$ strace bash -c "hoge" 2>&1 |grep fstatat| grep hoge
newfstatat(AT_FDCWD, "/usr/local/bin/hoge", 0x7ff32941e8, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/bin/hoge", 0x7ff32941e8, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/bin/hoge", 0x7ff32941e8, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/local/games/hoge", 0x7ff32941e8, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/games/hoge", 0x7ff32941e8, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/yoichinakayama/.local/bin/hoge", 0x7ff32941e8, 0) = -1 ENOENT (No such file or directory)
Après avoir recherché la variable d'environnement PATH, un message d'erreur est émis.
yoichinakayama@penguin:~$ strace bash -c "hoge" 2>&1 |grep "command not found"
write(2, "bash: hoge: command not found\n", 30bash: hoge: command not found
bash met en cache le chemin de la commande exécutée.
yoichinakayama@penguin:~$ type hostname
hostname is /bin/hostname
yoichinakayama@penguin:~$ hostname
penguin
yoichinakayama@penguin:~$ type hostname
hostname is hashed (/bin/hostname)
yoichinakayama@penguin:~$ hostname
penguin
Voyons également ce comportement.
yoichinakayama@penguin:~$ strace -f bash -c "hostname; hostname" 2>&1 |grep "\(execve\|fstatat\)"
...
newfstatat(AT_FDCWD, "/usr/local/bin/hostname", 0x7febd16b68, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/bin/hostname", 0x7febd16b68, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/bin/hostname", {st_mode=S_IFREG|0755, st_size=18440, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/hostname", {st_mode=S_IFREG|0755, st_size=18440, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/hostname", {st_mode=S_IFREG|0755, st_size=18440, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/hostname", {st_mode=S_IFREG|0755, st_size=18440, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/hostname", {st_mode=S_IFREG|0755, st_size=18440, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/hostname", {st_mode=S_IFREG|0755, st_size=18440, ...}, 0) = 0
[pid 2555] execve("/bin/hostname", ["hostname"], 0xc2b9008 /* 31 vars */) = 0
[pid 2556] execve("/bin/hostname", ["hostname"], 0xc2b9008 /* 31 vars */) = 0
Vous pouvez voir que la deuxième fois, il s'exécute sans recherche.
Vous pouvez voir que vous pouvez aller le retrouver en faisant hash -r
.
yoichinakayama@penguin:~$ strace -f bash -c "hostname; hash -r; hostname" 2>&1 |grep "\(execve\|fstatat\)"
...
newfstatat(AT_FDCWD, "/usr/local/bin/hostname", 0x7fc0d8aa08, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/bin/hostname", 0x7fc0d8aa08, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/bin/hostname", {st_mode=S_IFREG|0755, st_size=18440, ...}, 0) = 0
...
[pid 2598] execve("/bin/hostname", ["hostname"], 0x110de008 /* 31 vars */) = 0
...
newfstatat(AT_FDCWD, "/usr/local/bin/hostname", 0x7fc0d8aba8, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/bin/hostname", 0x7fc0d8aba8, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/bin/hostname", {st_mode=S_IFREG|0755, st_size=18440, ...}, 0) = 0
...
[pid 2599] execve("/bin/hostname", ["hostname"], 0x110de008 /* 31 vars */) = 0
Si vous spécifiez la commande avec un chemin absolu, la commande est exécutée sans rechercher le long du PATH.
yoichinakayama@penguin:~$ strace -f bash -c "/bin/hostname" 2>&1 |grep "\(execve\|fstatat\)"
execve("/bin/bash", ["bash", "-c", "/bin/hostname"], 0x7fec75a6c8 /* 31 vars */) = 0
newfstatat(AT_FDCWD, "/home/yoichinakayama", {st_mode=S_IFDIR|0755, st_size=622, ...}, 0) = 0
newfstatat(AT_FDCWD, ".", {st_mode=S_IFDIR|0755, st_size=622, ...}, 0) = 0
newfstatat(AT_FDCWD, "/home", {st_mode=S_IFDIR|0755, st_size=28, ...}, 0) = 0
newfstatat(AT_FDCWD, "/home/yoichinakayama", {st_mode=S_IFDIR|0755, st_size=622, ...}, 0) = 0
newfstatat(AT_FDCWD, ".", {st_mode=S_IFDIR|0755, st_size=622, ...}, 0) = 0
newfstatat(AT_FDCWD, "/usr/local/bin/bash", 0x7fff5c3fd8, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/bin/bash", 0x7fff5c3fd8, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/bin/bash", {st_mode=S_IFREG|0755, st_size=1016024, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/bash", {st_mode=S_IFREG|0755, st_size=1016024, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/bash", {st_mode=S_IFREG|0755, st_size=1016024, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/bash", {st_mode=S_IFREG|0755, st_size=1016024, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/bash", {st_mode=S_IFREG|0755, st_size=1016024, ...}, 0) = 0
newfstatat(AT_FDCWD, "/bin/bash", {st_mode=S_IFREG|0755, st_size=1016024, ...}, 0) = 0
execve("/bin/hostname", ["/bin/hostname"], 0x3d55e008 /* 31 vars */) = 0
Je l'ai vérifié sur le terminal du Chromebook.
yoichinakayama@penguin:~$ uname -a
Linux penguin 5.4.39-04075-gfc7cb60d7f13 #1 SMP PREEMPT Sun May 10 10:47:48 PDT 2020 aarch64 GNU/Linux
yoichinakayama@penguin:~$ bash --version
GNU bash, version 4.4.12(1)-release (aarch64-unknown-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Recommended Posts