回答:
答えは多かれ少なかれls
、外部の実行可能ファイルです。を実行すると、その場所を確認できますtype -p ls
。
では、なぜls
シェルに組み込まれていないのですか?さて、なぜそれが必要なのでしょうか?シェルの役割は、使用可能なすべてのコマンドを網羅することではなく、それらを実行できる環境を提供することです。いくつかの近代的なシェルが持っているecho
、printf
としていない組み込みコマンド、として彼らの同類技術的に組み込みコマンドでなければならないが、彼らは(主にタイトなループで)繰り返し実行され、パフォーマンス上の理由からそう作られています。それらをビルトインにしないと、シェルはそれらを呼び出すたびに新しいプロセスを分岐して実行する必要があり、非常に遅くなる可能性があります。
少なくとも、ls
外部実行ファイルであるを実行するには、システムコールのexecファミリのいずれかを実行する必要があります。フォークせずにこれを行うことはできますが、使用しているプライマリシェルは置き換えられます。次の操作を行うと、そのインスタンスで何が起こるかを確認できます。
exec ls; echo "this never gets printed"
シェルのプロセスイメージが置き換えられるため、これを実行すると現在のシェルにアクセスできなくなります。lsを実行した後もシェルを実行し続けるには、コマンドをシェルに組み込む必要があります。
フォークを使用すると、プライマリシェルではないプロセスを置き換えることができます。つまり、後でシェルを実行し続けることができます。
echo
、printf
など
cd
外部実行可能ファイルではないのですか?
Bashのリファレンスマニュアルの状態:
組み込みのコマンドは、個別のユーティリティでは取得できない、または不便な機能を実装するために必要です。
つまり、シェルは、次の場合にのみ組み込みコマンドを含むように設計されています。
このls
コマンドは、上記の要件のいずれにも適合しません。
ただし、ls
組み込みとして実装されるのを防ぐプログラミング上の制約はありません 。これは、bashインタープリターと同じプロセスで実行されます。コマンドの設計上の理由ではありませんシェルの組み込みとして実装されは次のとおりです。
最初の理由について-あなたはシェルをできるだけ独立し、弾力性のあるものにしたいです。ls
「まだ応答しようとしても応答しない」NFSマウントでシェルがスタックするのは望ましくありません。
2番目の理由について-多くの場合、Busyboxまたは異なるls
実装を持つ他のファイルシステムを使用するシステムにシェルを使用したい場合があります。または、ls
実装が異なるOSで同じシェルソースを使用することもできます。
3番目の理由に関して- シェルインタープリターと同じプロセスでfind . -type d | xargs ls -lad
実装することが困難または不可能であるような式の場合ls
。
4番目の理由について-一部のls
コマンドは完了するまでに時間がかかる場合があります。それまでの間、シェルに何か他のことを続けさせたい場合があります。
ls
。できますが、複雑になります。
bash
出力alias | grep ls
。入力cat /etc/passwd | while read a; do echo "$a"; done
ls
別のプロセスを必要としません。実際には、個別のプロセスを必要とするコマンドはほとんどありません。特権を変更する必要があるコマンドのみです。
原則として、シェルは、コマンドをビルトインとして実装する必要がある場合にのみ、コマンドをビルトインとして実装します。コマンドのようにalias
、cd
、exit
、export
、jobs
、...ので、読み取りまたはシェルのいくつかの内部状態を変更し、する必要が別々のプログラムにすることはできません。そのような要件のないコマンドは、個別のコマンドにすることができます。このように、これらは任意のシェルまたは他のプログラムから呼び出すことができます。
bashのビルトインのリストを見ると、次のビルトインのみが個別のコマンドとして実装できます。それらの一部については、機能がわずかに失われます。
command
—しかし、PATH
正しくセットアップされていない可能性があり、セットアップのcommand
一部としてスクリプトが使用している状況では、その有用性が失われます。echo
—それは効率のための組み込みです。help
—別のデータベースを使用できますが、シェル実行可能ファイルにヘルプテキストを埋め込むと、シェル実行可能ファイルを自己完結させることができます。kill
—組み込み機能を使用することには2つの利点があります。プロセスIDに加えてジョブの指定を認識できること、および別のプロセスを開始するのに十分なリソースがない場合でも使用できることです。printf
—と同じ理由echo
で、また-v
出力を変数に入れるオプションをサポートします。pwd
—ビルトインは、論理的な現在のディレクトリトラッキングの追加機能を提供します(シンボリックリンクを展開する代わりにそのまま残します)。test
—それは効率のためのビルトインです(また、bashはいくつ/dev/fd/…
かのオペレーティングシステムで呼び出されるファイルでいくつかの魔法を行います)。いくつかのシェルは、かなりの数の追加のビルトインを提供します。sashがあります。これは、緊急修理用のスタンドアロンバイナリとして設計されたシェルです(一部の外部コマンドが使用できない場合があります)。とls
呼ばれる組み込みの、および-ls
などの他のツールが-grep
あり-tar
ます。Sashのビルトインは、本格的なコマンドよりも機能が少ないです。Zshは、zsh / filesモジュールで同様のビルトインを提供しています。にはありませんがls
、ワイルドカード拡張(echo *
)がありzstat
、同様の機能を果たすことができます。
ここで人々が見逃しているのは、ls
Linux上のGNU プログラムの複雑なせん断だと思います。実行ファイルサイズの比較ls
へbash
とdash
私のDebianシステム上のシェルを、我々はそれが非常に大きいことを参照してください。
graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30 2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls
ls
GNUバージョンと同等のフル機能を含めると、bash
実行可能ファイルのサイズが10%増加します。フルシェルとほぼ同じサイズdash
です!
ほとんどのシェルビルトインが選択されるのは、外部実行可能ファイルができない方法でシェルと統合するため(質問が指摘しますcd
が、別の例はkill
bashジョブコントロールとの統合のbashバージョンです)、または実装する非常に単純なコマンドであるためです大きな速度対サイズの見返りを与えます(true
そしてfalse
、それは得られるほど簡単です)。
GNUにls
は長い開発サイクルがあり、結果の表示/表示方法をカスタマイズするためのオプションを実装しています。デフォルトで組み込みlsを使用すると、この機能が失われるか、シェルの複雑さとサイズが大幅に増加します。
これはあなたが探していることをします:
printf "%s\n" *
また、配列にファイル名を保存できます:
files=(`printf "%s\n" *`) #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done
しかし、名前のスペースは気にしません
これは変数に渡され、スペースを気にします:
printf "%s\n" * | while read a; do echo $a; done
ls
外部プログラム、であるecho *
かecho * .*
(シェルオプションに応じて)フォークせずにファイルをリストのかなり良いの仕事をしていません。