この質問の目的は、特定のコンピューティング問題を解決することではなく、好奇心に答えることです。問題は、なぜシェル実装にPOSIX必須ユーティリティが一般的に組み込まれていないのかということです。
たとえば、基本的にいくつかの小さなテキストファイルを読み取り、それらが適切にフォーマットされていることを確認するスクリプトがありますが、私のマシンでは、大量の文字列操作のため、実行に27秒かかります。この文字列操作は、さまざまなユーティリティを呼び出すことによって何千もの新しいプロセスを作成するため、速度が低下します。いくつかのユーティリティ、つまりgrep
、sed
、cut
、tr
、およびexpr
が組み込まれていれば、かなり自信があります。 、その後、スクリプトは1秒以内に実行されます(Cでの私の経験に基づく)。
これらのユーティリティをビルドすると、シェルスクリプトのソリューションが許容できるパフォーマンスを備えているかどうかに違いが生じる多くの状況があるようです。
明らかに、これらのユーティリティを組み込まないように選択された理由があります。たぶん、システムレベルで1つのバージョンのユーティリティを使用することで、さまざまなシェルがそのユーティリティの異なるバージョンを複数使用することを回避できます。非常に多くの新しいプロセスを作成するオーバーヘッドを維持する他の多くの理由は本当に考えられません。POSIXは、それぞれがPOSIXである限り、さまざまな実装を持つことはそれほど問題に見えないユーティリティについて十分に定義しています。準拠。少なくとも、それほど多くのプロセスを持つことの非効率性ほど大きな問題ではありません。
シェルスクリプトは、そのような速度で実行することは想定されていません。スクリプトの速度を向上させたい場合は、Perlで試してください。それでも遅すぎる場合は、Javaまたはcなどの静的型付き言語に移行するか、遅すぎる部分を実行するPerl用のCモジュールを作成する必要があります。
Shellはプロトタイピングの最初のレベルです。Shellで概念を証明できたら、Shellのエーカーを必要とするより多くの境界チェックを実行できる、より優れたスクリプト言語に移行します。
Unix OSには、大局を構成する明確に定義されたタスクを実行する多くの小さなプログラムが含まれることが期待されています。これは、より大きなプログラムを区分するので、良いことです。たとえばqmailを見て、それをsendmailと比較してください。 qmailは多くのプログラムで構成されています:
http://www.nrg4u.com/qmail/the-big-qmail-picture-103-p1.gif
ネットワークデーモンを利用しても、キューマネージャの利用には役立ちません。
POSIX必須ユーティリティがシェルに組み込まれていないのはなぜですか?
POSIX準拠であるため、システムは必須1 ほとんどのユーティリティをスタンドアロンコマンドとして提供します。
それらが組み込まれていると、シェルの内部と外部の2つの異なる場所に存在する必要があることを意味します。もちろん、ビルトインへのシェルスクリプトラッパーを使用して外部バージョンを実装することは可能ですが、非シェルアプリケーションがユーティリティを呼び出すのは不利です。
BusyBox は、内部に多くのコマンドを実装し、それ自体へのリンクを使用してスタンドアロンバリアントを提供することにより、提案したパスをとったことに注意してください。 1つの問題は、コマンドセットが非常に大きくなる可能性がある一方で、実装は多くの場合、標準のサブセットであるため、準拠していません。
また、少なくとも ksh93
、 bash
およびzsh
さらに、実行中のシェルが共有ライブラリからビルトインを動的にロードするためのカスタムメソッドを提供します。技術的には、すべてのPOSIXユーティリティを実装して組み込みとして利用できるようにするものはありません。
最後に、新しいプロセスの生成は、最近のOSでは非常に高速な操作になっています。実際にパフォーマンスの問題に直面している場合は、スクリプトをより高速に実行するためのいくつかの改善点があるかもしれません。
ただし、すべての標準ユーティリティ(表の通常の組み込みを含むが、特別な組み込みユーティリティで説明されている特別な組み込みは除く) 、は、POSIX.1-2008のシステムインターフェースボリュームで定義されているexecファミリーの関数を介してアクセスできるように実装する必要があります。それを必要とする標準ユーティリティ(env、find、Nice、Nohup、time、xargs)から直接呼び出すことができます。
BASHリファレンスマニュアル から、
組み込みコマンドは、別個のユーティリティで取得することが不可能または不便な機能を実装するために必要です。
聞いたことがあると思いますが、UNIXの哲学は、すべて機能が制限されている複数のアプリケーションに大きく依存しています。各ビルトインには、ビルトインされている非常に良い理由があります。それ以外はすべて含まれていません。より興味深い質問のクラスは、「なぜ正確にispwd
組み込みですか?」
AT&T Software Toolkit(現在、コアチームが去ってからgithubで休眠中)の履歴を見ると、これはまさに彼らがAT&T Kornシェル(ksh93)で行ったことと同じです。
パフォーマンスは常にksh93メンテナの動機の一部であり、kshをビルドするとき、動的にロードされるライブラリとして多くの一般的なPOSIXユーティリティをビルドすることを選択できます。これらのコマンドを/opt/ast/bin
のようなディレクトリ名にバインドすることにより、$PATH
でのディレクトリ名の位置に基づいて、使用するコマンドのバージョンを制御できます。
例:
cat chmod chown cksum cmp cp cut date expr fmt head join ln
mkdir mkfifo mktemp mv nl od paste rm tail tr uniq uuencode wc
完全なリストは github ast リポジトリにあります。
Astツールのほとんどには独自の出所があり、より一般的なgnu実装とは大きく異なることに注意してください。 AT&T Researchチームは、コードを共有できないときに相互運用性を実現するための公式の基準を遵守しました。
したがって、すべての特定の欲求を満たすために、元のツールを最適化するためにリソースを整理しませんでした。私たちが説明する必要があるのは、この特定の欲求を実装するためにどれだけの費用がかかるだろうということです。
POSIXは、ユーティリティについて十分に定義しているため、異なる実装を行うことはそれほど問題のようには思えません。
これは悪い仮定です:-P。
Post-POSIXシステムは、正当な理由により、より強力で便利になり続けています。事後基準として、実際には追いつきません。
Ubuntuは、古いSystem V initブートプロセスを最適化するために、簡素化されたPOSIXシェルをスクリプトに切り替える取り組みを開始しました。失敗したとは言っていませんが、クリーンアップする必要のある多くのバグを引き起こしていました。「bashisms」、bash
機能が利用可能であると想定しながら/bin/sh
の下で実行されたスクリプト。
POSIX shは、優れた汎用プログラミング言語ではありません。そのprimaryの目的は、対話型シェルとしてうまく機能することです。コマンドをスクリプトに保存し始めるとすぐに、 Turing tarpit に近づくことに注意してください。例えば。通常のパイプラインの途中で障害を 検出することはできません 。 bash
はこれにset -o pipefail
を追加しましたが、これはPOSIXにはありません。
true
よりも複雑なほぼすべてのユーティリティによって、同様の便利だが標準化されていない機能が提供されます。
概説するタスクのクラスでは、Awk、Perl、そして今日のPythonに大まかな線を引くことができます。さまざまなツールが作成され、独立して進化しました。あなたは期待しますか? GNU Awkはlibutilposixextendedに包含されるのですか?
私が今あなたに指摘できる普遍的により良いアプローチがあると言っているのではありません。 Pythonが苦手です。 Awkは驚くほど強力ですが、GNU Awkに固有のいくつかの機能に不満を感じています。しかし、ポイントは、おそらくファイルの行から)多数の文字列を個別に処理することではなかったことです。 POSIXシェルの設計目標。
質問もあります:どのシェルに組み込みますか?
ほとんどのUnix/Linuxシステムには、独立して開発された複数の異なるシェルがあります(sh/bash/korn/???)。シェルにツールを組み込むと、シェルごとにこれらのツールの実装が異なることになります。これによりオーバーヘッドが発生し、どのシェルを呼び出したかに応じて、grepなどのさまざまな機能/バグが発生する可能性があります。
多くの人がよく答えています。私はそれらの答えをほめたたえるだけです。 UNIXの哲学は、toolが1つのことを実行し、それをうまく実行することだと思います。すべてを網羅するツールを作成しようとすると、失敗する場所がさらに増えます。このように機能を制限すると、信頼性の高いツールセットになります。
また、sedやgrepなどの機能がシェルに組み込まれている場合は、コマンドから簡単に呼び出すことができます。いつご希望ですか?
最後に、BASHにしたい機能の一部がBASHにあることを考慮してください。たとえば、BASHでのREマッチングの機能は、=〜二項演算子を使用して実装されます(詳しくは、マニュアルページの シェル文法 を参照してください)。 if)の[[]]構文の説明を参照してください。非常に簡単な例として、2つの16進数をファイルで検索するとします。
while read line; do
if [[ $line =~ 0x[[:xdigit:]]{2} ]]; then
# do something important with it
fi
done < input_file.txt
sed-like機能については、同じmanページの The Expansion heading のParameter Expansionを見てください。 sedを連想させる、実行可能な多くのことがわかります。私はほとんどの場合、sedを使用してテキストの置換タイプを変更します。上記から構築:
# this does not take into account the saving of the substituted text
# it shows only how to do it
while read line; do
${line/pattern/substitution}
done < input_file.txt
しかし、結局、上記は「より良い」ですか?
grep -E "[[:xdigit:]]{3}" input_file.txt
sed -e 's/pattern/substitution/' input_file.txt
これは歴史的な事故だと思います。
UNIXが1960年代後半から1970年代初頭に作成されたとき、コンピュータには現在のメモリと同じくらいのメモリがありませんでした。当時は、これらの機能をすべてShellビルトインとして実装することが可能でしたが、メモリの制限により、実装できる機能の量を制限するか、メモリ不足のリスクやゴミ箱の交換を行う必要がありました。問題。
一方、特定の機能を個別のプログラムとして実装し、新しいプロセスを開始するために必要な2つのシステムコールをできる限り軽くすることで、これらの問題がなく、依然として適切に実行されるスクリプト環境を作成できます。速度。
もちろん、それらが別々のプロセスとして実装されると、人々はそれらをnotシェルであるプログラムから起動し、その後、そのようにしておく必要があります。
ただし、一部の機能を2回実装できないと言っているわけではありません。実際、一部のシェルは、Shellビルトインとして外部プログラムであるはずの機能を実装しています。たとえば、bashはecho
コマンドを組み込みとして実装していますが、/usr/bin/echo
もあります。