「ls」を実行するために別のプロセスが必要なのはなぜですか?


14

ls実行に別のプロセスが必要なのはなぜですか?私cdはフォークのメカニズムによってコマンドのようなものを実行できない理由を知っていますが、フォークせずに実行された場合に害はありますlsか?


1
ls外部プログラム、であるecho *echo * .*(シェルオプションに応じて)フォークせずにファイルをリストのかなり良いの仕事をしていません。
ゲリット14年

これはさらに優れています:printf "%s \ n" *
コスタ14年

シェルの多様性に関する注意:tcshにはのls-Fような機能が組み込まれていls -Fます。効率化のためにあります。-F通常、どちらを使用するかは常に得策です。他のオプションを指定すると、外部コマンドにパントします。

回答:


18

答えは多かれ少なかれls、外部の実行可能ファイルです。を実行すると、その場所を確認できますtype -p ls

では、なぜlsシェルに組み込まれていないのですか?さて、なぜそれが必要なのでしょうか?シェルの役割は、使用可能なすべてのコマンドを網羅することではなく、それらを実行できる環境を提供することです。いくつかの近代的なシェルが持っているechoprintfとしていない組み込みコマンド、として彼らの同類技術的に組み込みコマンドでなければならないが、彼らは(主にタイトなループで)繰り返し実行され、パフォーマンス上の理由からそう作られています。それらをビルトインにしないと、シェルはそれらを呼び出すたびに新しいプロセスを分岐して実行する必要があり、非常に遅くなる可能性があります。

少なくとも、ls外部実行ファイルであるを実行するには、システムコールのexecファミリのいずれかを実行する必要があります。フォークせずにこれを行うことはできますが、使用しているプラ​​イマリシェルは置き換えられます。次の操作を行うと、そのインスタンスで何が起こるかを確認できます。

exec ls; echo "this never gets printed"

シェルのプロセスイメージが置き換えられるため、これを実行すると現在のシェルにアクセスできなくなります。lsを実行した後もシェルを実行し続けるには、コマンドをシェルに組み込む必要があります。

フォークを使用すると、プライマリシェルではないプロセスを置き換えることができます。つまり、後でシェルを実行し続けることができます。


1
私は彼がls(1)がシェルの組み込み機能ではない理由を尋ねていると思います。アップ、そしてそれをシェルに「組み込む」ことの大部分のダウン。
llua 14年

@llua私はそれについていくつかの情報、およびの例外ケースを追加echoprintfなど
クリス・ダウン

ビルトインされているものとそうでないものがある理由は必ずしも明確ではありません。たとえば、なぜcd外部実行可能ファイルではないのですか?
ファヒムミタ14

@FaheemMitha POSIX準拠のオペレーティングシステムに外部cd実行可能ファイルがあります(こちらを参照)。ただし、現在のプロセスで実際にchdir()する場合は、シェルに組み込む必要があります。
クリスダウン14年

なぜls外部にあるかは習慣になっていますが、シェルに実装することもできます。busyboxを参照してください。

15

Bashのリファレンスマニュアルの状態:

組み込みのコマンドは、個別のユーティリティでは取得できない、または不便な機能を実装するために必要です。

つまり、シェルは、次の場合にのみ組み込みコマンドを含むように設計されています。

  1. POSIX標準で必要
  2. ジョブ制御ビルトインなど、シェル自体へのアクセスを必要とするコマンド
  3. OSに依存せず、printfなどのビルトインとして実装すると実行効率が向上する、非常にシンプルなコマンド

このlsコマンドは、上記の要件のいずれにも適合しません。

ただしls組み込みとして実装されるのを防ぐプログラミング上の制約はありません 。これは、bashインタープリターと同じプロセスで実行されます。コマンドの設計上の理由ではありませんシェルの組み込みとして実装されは次のとおりです。

  1. シェルはファイルシステムとは別にする必要があります-組み込みコマンドがファイルシステムまたは周辺機器の正しい動作に依存することはありません
  2. ファイルシステムタイプまたはOSに依存する可能性があるコマンドは、別個の実行可能ファイルである必要があります
  3. パイプでやり取りするコマンドは別のプロセスである必要があります
  4. バックグラウンドで実行するコマンドは、別個の実行可能ファイルである必要があります
  5. 多数の可能なパラメーターを持つコマンドは、個別の実行可能ファイルにより適切に実装されます
  6. 起動するシェルのタイプ(bash、csh、tsh、...)に関係なく、同じ出力を持つコマンドは、スタンドアロンの実行可能ファイルである必要があります。

最初の理由について-あなたはシェルをできるだけ独立し、弾力性のあるものにしたいです。ls「まだ応答しようとしても応答しない」NFSマウントでシェルがスタックするのは望ましくありません。

2番目の理由について-多くの場合、Busyboxまたは異なるls実装を持つ他のファイルシステムを使用するシステムにシェルを使用したい場合があります。または、ls実装が異なるOSで同じシェルソースを使用することもできます。

3番目の理由に関して- シェルインタープリターと同じプロセスでfind . -type d | xargs ls -lad実装することが困難または不可能であるような式の場合ls

4番目の理由について-一部のlsコマンドは完了するまでに時間がかかる場合があります。それまでの間、シェルに何か他のことを続けさせたい場合があります。


注:参照してください。この便利なポストをすることによりウォーレン若い同様の質問に対して。


別個のコマンドである場合は出力のパイピングの容易さを逃し、シェルプリミティブを別個の実行可能ファイルにパイピングするために必要なすべてのプログラミングを逃しました。
ブルースエディガー14年

@BruceEdiger:尊敬されるBEからコメントを受け取るのはなんて嬉しいことでしょう。ありがとう!私は理由3があなたのコメントをカバーしていると信じています。
ジョナサンベンアブラハム14年

1
外部プロセスのパイプを処理し、仮想コマンドのような内部コマンドの出力を外部プロセスにパイプしなければならない場合、シェル自体のソースコードがどれほど複雑になるかという考えに沿って考えていましたls。できますが、複雑になります。
ブルースエディガー14年

1
あなたの5つのポイントのすべてが無意味ではないにしても、私はほとんど恐れています。1:lsは(できれば)ファイルシステムの実装から独立しています。標準ライブラリとアプリケーションへの一貫したインターフェースを提供するのはカーネル次第です。2:lsは、シェルよりもOSへの依存度が低い可能性があります。3:シェルは、パイプラインの組み込みを確実に許可します。4:シェルを使用すると、ビルトインをバックグラウンドで確実に実行できます。5:それは非常に主観的です。
jlliagre

1
@ JonathanBen-Avraham @BruceEdigerシェルは、サブシェルを持つビルトインのパイプケースを既に処理していませんか?例えばbash出力alias | grep ls。入力cat /etc/passwd | while read a; do echo "$a"; done
マット14年

2

ls別のプロセスを必要としません。実際には、個別のプロセスを必要とするコマンドはほとんどありません。特権を変更する必要があるコマンドのみです。

原則として、シェルは、コマンドをビルトインとして実装する必要がある場合にのみ、コマンドをビルトインとして実装します。コマンドのようにaliascdexitexportjobs、...ので、読み取りまたはシェルのいくつかの内部状態を変更し、する必要が別々のプログラムにすることはできません。そのような要件のないコマンドは、個別のコマンドにすることができます。このように、これらは任意のシェルまたは他のプログラムから呼び出すことができます。

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、同様の機能を果たすことができます。


2

ここで人々が見逃しているのは、lsLinux上のGNU プログラムの複雑なせん断だと思います。実行ファイルサイズの比較lsbashdash私の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

lsGNUバージョンと同等のフル機能を含めると、bash実行可能ファイルのサイズが10%増加します。フルシェルとほぼ同じサイズdashです!

ほとんどのシェルビルトインが選択されるのは、外部実行可能ファイルができない方法でシェルと統合するため(質問が指摘しますcdが、別の例はkillbashジョブコントロールとの統合のbashバージョンです)、または実装する非常に単純なコマンドであるためです大きな速度対サイズの見返りを与えます(trueそしてfalse、それは得られるほど簡単です)。

GNUにlsは長い開発サイクルがあり、結果の表示/表示方法をカスタマイズするためのオプションを実装しています。デフォルトで組み込みlsを使用すると、この機能が失われるか、シェルの複雑さとサイズが大幅に増加します。


1

cdはシェルに組み込まれてlsいます/bin/ls。これは、で表示される別のプログラムです。


0

これはあなたが探していることをします:

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.