sudo: command not found はなぜ起こる? – シェル内部コマンドと外部コマンド

Linux

皆さまこんにちは、ウチイダユウゴです!

以前に、sudo cd がうまく動かないときの対処法についてブログに書きました。

あれからけっこう経つのですが、多くの人がこの記事を見に来てくれるようです。

最近、42 Tokyoの課題の中でシェルの実装について調べる機会がありました。

その内容をふまえて、sudo cd がエラーになる原因などをもうちょっと説明してみたいと思います。

sudo が実行するのは「外部コマンド」

以前取り上げた通りですが、sudoコマンドからcd を行うとエラーになります。

$ sudo cd ~
sudo: cd: コマンドが見つかりません

「コマンドがない」というのはパスの通っているディレクトリ内に、cdの実行プログラムがない、ということです。

実行プログラムが独立して存在するコマンドを「外部コマンド」とよびます。sudo は外部コマンドを別のユーザー権限で実行します。

一方、cdは「内部コマンド」という種類のコマンドで、外部にある実行プログラムが呼び出されるのではなく、シェルの機能の一部として処理されるコマンドです。

内部コマンドと外部コマンドの見分け方

外部コマンドと内部コマンドはどんな違いがあるのでしょう。

誤解を恐れずざっくりいうと、「シェル自身の状態を変更する必要がある内容」は内部コマンドである可能性が高いです。

これまで例に挙げてきたcd は、「シェルで扱っているカレントディレクトリを変更する」という機能なので、外部コマンドではなく内部コマンドです。

シェルの実行を終了する exit コマンドも内部コマンドです。

さらに、環境変数の設定を行う export や declare といったコマンドも、内部コマンドです。

他にもいくつか内部コマンドがあります。あるコマンドが内部コマンドかどうかを調べたい場合、bashの場合は help コマンドで内部コマンドの一覧が表示されます。

$ help
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
These shell commands are defined internally.  Type `help' to see this list.
Type `help name' to find out more about the function `name'.
Use `info bash' to find out more about the shell in general.
Use `man -k' or `info' to find out more about commands not in this list.

A star (*) next to a name means that the command is disabled.

# わかりやすいところだけ抜粋 ---

alias [-p] [name[=value] ... ]
bg [job_spec ...]
bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-com>
break [n]
cd [-L|[-P [-e]] [-@]] [dir]
command [-pVv] command [arg ...]

# --- 以下略

ちなみに、それぞれのコマンドの詳細は、 help [内部コマンド名] で表示することができます。

内部コマンドはman で探しても出てきません。

コマンド名がわかっていれば、type [コマンド名] でも調べることができます。

$ type cd
cd is a shell builtin # <- シェルのビルトイン(内部コマンド)と表示される

内部コマンドだけど、sudoで使える場合がある?

さて、さきほどsudoは内部コマンドを実行できないと説明しました。

ここでちょっと気を付けておきたいのが、あたかも内部コマンドを実行できたようにふるまう場合があるということです。

たとえば、printfとか。

$ type printf
printf is a shell builtin # <- printfは内部コマンド
$ sudo printf "hello world, from printf command! \n"
hello world, from printf command! # <- sudo printf が実行された

shell buitin とされていながら、sudo で実行できてしまいます。

これは、内部コマンドのほかに、「printf」という外部コマンドも存在しているからです。

type -a [コマンド名] で、そのコマンドが複数インストールされている場合に一覧で表示してくれます。

printf についてみてみると、

$ type -a printf
printf is a shell builtin
printf is /usr/bin/printf
printf is /bin/printf

ウチイダの環境では、こんなふうにprintfが外部コマンドとしてもインストールされていました。

sudo printf のときは、外部コマンドのprintf が実行されていたのですね。

まとめ

改めてsudo と外部コマンド/内部コマンドについて知見が得られたので、ブログを書いてみました。

今回の内容をまとめると、こんな感じです。

  • sudo は外部コマンドを実行するもので、シェルの内部コマンドは実行できない
  • 内部コマンドの一覧は、help コマンドで確認できる(※ bashの場合)
  • type [コマンド名] でも、コマンドが内部コマンドかどうかを調べられる
  • 内部コマンドと同じ名称で外部コマンドがインストールされている場合、sudo でも実行できる
  • ただし、その場合実行されるのはあくまで外部コマンドのほう。内部コマンドと実装や仕様が異なる可能性があるので注意

調べれば調べるほど奥が深いシェルの世界です。

最終的には公式情報に当たるのが正確なので、気合入れてマニュアルも見ていこうと思います。。。

https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html

以上です!最後までお読みいただきありがとうございました(/・ω・)/

コメント

タイトルとURLをコピーしました