POSIX必須ユーティリティがシェルに組み込まれていないのはなぜですか?


45

この質問の目的は、特定のコンピューティング問題を解決することではなく、好奇心に答えることです。問題は、なぜPOSIXの必須ユーティリティがシェル実装に組み込まれていないのですか?

たとえば、基本的にいくつかの小さなテキストファイルを読み取り、それらが適切にフォーマットされていることを確認するスクリプトがありますが、かなりの量の文字列操作のために、マシンで実行するのに27秒かかります。この文字列操作は、さまざまなユーティリティを呼び出すことで数千の新しいプロセスを作成するため、速度が低下します。私はユーティリティのいくつかは、すなわち、中に建設された場合のことをかなり確信していますgrepsedcuttr、およびexpr、スクリプトが第二に実行します以下(Cでの私の経験に基づきます)。

これらのユーティリティをビルドすると、シェルスクリプトのソリューションのパフォーマンスが許容範囲内であるかどうかが異なる場合が多いようです。

明らかに、これらのユーティリティをビルトインしないことを選択した理由があります。システムレベルで1つのバージョンのユーティリティを使用すると、そのユーティリティの複数の異なるバージョンがさまざまなシェルで使用されることがなくなります。私は本当に多くの新しいプロセスを作成するオーバーヘッドを維持するために他の多くの理由を考えることはできません。準拠しています。少なくとも非常に多くのプロセスを持つことの非効率性ほど大きな問題ではありません。


15
27秒が遅すぎる場合は、Python、Perl、またはその他のセミコンパイル言語を使用できます。または、スクリプトの遅い部分を投稿し、改善を依頼してください。3つまたは4つのコマンドを使用しているのに、1つ(速い方)のコマンドが実行される可能性があります。
ロアイマ

8
残念ながら、シェルはヘビーデューティタスク用に実際に作られたわけではなく、シェルスクリプトだけで逃げることができる時代から世界は大きく変わりました。私はroaimaに同意する-あらゆる合理的なシステム管理者は、ハンドルのすべてにシェルを期待するPythonやPerlのために行くとはならない
Sergiy Kolodyazhnyy

16
シェルの主な目的は、データを直接操作するのではなく、他のプログラムを実行することです。長年にわたり、それらによって提供される一部の外部プログラムまたは機能(グロビング、算術printfなど)は、十分有用であるとみなされたときにシェルに組み込まれてきました。
chepner

8
スクリプトをcodereview.stackexchange.comに投稿すると、レビュアーはスクリプトを大幅に高速化するための提案を行うことができると確信しています(または、少なくともシェルではなくPython / etcで記述する必要がある理由を指摘します)。
chepner

5
@Kyle:awkあなたがそうでなければ使用して実装するかもしれないというスクリプトを実装するために(非常に高速であること)POSIXで必須のユーティリティであり、特によく適しているsedcuttrgrep、およびexprシェルスクリプトで。
公称動物

回答:


11

シェルスクリプトは、このタイプの速度で実行することは想定されていません。スクリプトの速度を改善したい場合は、perlで試してください。それでも遅すぎる場合は、javaやcなどの静的に型付けされた言語に移行するか、遅すぎる部分を実行するperl用のCモジュールを記述する必要があります。

シェルはプロトタイピングの第1レベルです。シェルでコンセプトを証明できれば、より多くの境界チェックを行うことができるより優れたスクリプト言語に移行します。

Unix OSには、全体像を構成する明確に定義されたタスクを実行する多くの小さなプログラムが含まれることが期待されています。これは、より大きなプログラムを区分するので良いことです。たとえばqmailを見て、sendmailと比較してください。qmailは多くのプログラムで構成されています:

http://www.nrg4u.com/qmail/the-big-qmail-picture-103-p1.gif

ネットワークデーモンを悪用しても、キューマネージャーを悪用することにはなりません。


OPは、コードの速度を改善するための提案を特に求めませんでした。問題は、特定のユーティリティがcdやなどの組み込みではない理由pwdです。
スティーブンC

4
本当です。答えは、モノリシックとコンパートメント化の違いを表現し、この好意の理由を示すことでした。
エド・ネビル


1
@StephenC cdはビルトインです。サブプロセスの作業ディレクトリを変更しても親プロセスには影響しないため、実際には必要です。
ジョナス

67

POSIX必須ユーティリティがシェルに組み込まれていないのはなぜですか?

POSIX準拠であるため、システムはほとんどのユーティリティをスタンドアロンコマンドとして提供する必要あります1

それらをビルトインすると、シェルの内側と外側の2つの異なる場所に存在する必要があることを意味します。もちろん、ビルトインへのシェルスクリプトラッパーを使用して外部バージョンを実装することは可能ですが、それはユーティリティを呼び出す非シェルアプリケーションにとって不利になります。

BusyBoxは、多くのコマンドを内部に実装し、それ自体へのリンクを使用してスタンドアロンのバリアントを提供することで、提案されたパスを使用したことに注意してください。1つの問題は、コマンドセットが非常に大きくなる可能性がある一方で、実装が標準のサブセットであることが多いため、準拠していないことです。

注また、その少なくともksh93bashおよびzsh共有ライブラリから動的にロード組み込みコマンドに実行しているシェルのカスタム方法を提供することによって、さらに行きます。技術的には、すべてのPOSIXユーティリティを実装し、ビルトインとして使用可能にすることを妨げるものはありません。

最後に、新しいプロセスの生成は、最新のOSでは非常に高速な操作になりました。実際にパフォーマンスの問題に見舞われている場合は、スクリプトの実行を高速化するためのいくつかの改善点があるかもしれません。

1 POSIX.1-2008

ただし、表の通常のビルトインを含むすべての標準ユーティリティは、特別なビルトインユーティリティで説明されている特別なビルトインではなく、execファミリを介してアクセスできるように実装する必要があります。 POSIX.1-2008のSystem Interfacesボリュームで定義されているように機能し、それを必要とする標準ユーティリティ(env、find、nice、nohup、time、xargs)から直接呼び出すことができます。


4
これは正しい答えですが、これらのユーティリティのインターフェイスは一般にstdin / stdout経由であるため、それらのすべてがbashの組み込みルーチンとしても実装されていても、事実上必要であると付け加えます自体をフォークし、とにかく、パイプライン内の各コマンドに対してパイプを作成するために、これだけの限界利益があるだろう
Chunko

2
@Chunkoはい。ただし、サブシェルはfork / exec'edプロセスよりも軽量です。
jlliagre

3
@slebetmanあなたは私の要点を逃しています。サブシェルは、Linux上で実行されているかどうかに関係なく、スレッドでも実行プロセスでもありません。サブシェルは親のクローンであり、後に続かfork ないexec ; によって作成されます。forkはに比べて非常に軽量な操作execです。
jlliagre

3
busyboxビルトインは、ビルトインnoforkよりもオーバーヘッドが10倍少ない と測定しました。ビルトインnoexecは、別のバイナリのfork + execよりもオーバーヘッドが5倍少ないです。unix.stackexchange.com/a/274322/29483による定義 busyboxがnoforkすべてではないことは興味深いですが、メモリをクリーンアップしないことでbusyboxコードの一部が短縮され、短命のプロセスに依存していることがわかります。
sourcejedi

1
@jlliagre:Linuxでは、フォークがプロセスを作成します。おそらく欠けている点は、Linuxでプロセスを最適化しているため、開発者が軽量化をさらに進める利点はないと判断したことです。基本的に、Linuxではプロセスはスレッドと同じくらい軽量です。
slebetman

9

BASHリファレンスマニュアル

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

聞いたことがあると思いますが、UNIXの哲学は、すべて機能が制限されている複数のアプリケーションに大きく依存しています。各組み込みには、組み込みの理由が非常にあります。他のすべてはそうではありません。より興味深いクラスの質問は、「なぜ正確 pwd組み込まれているのか」という線に沿っていると思います。


2
一言で言えば:モジュール性
ペシュケ

2
/ bin / pwdが存在します。cdここでは、別のツールとして実装することが不可能なもののより良い例になると思います。
オスカースコグ

1
@OskarSkogそれがポイントでした。 cd組み込まなければpwdならない、しない。では、なぜbash実装者はそれを含めることを選んだのですか?
スティグヘマー

1
...これは、unix.stackexchange.com / questions / 145479で覆われています
JdeBP

@StigHemmer /bin/bashは存在しますが、組み込みのままです。gnu.org/software/bash/manual/html_node/にあるビルトインの
Stephen C

8

AT&Tのメンバーは同じことを自問しました

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チームは公式の基準に従いました。これは、コードを共有できなかったときに相互運用性を実現する方法でした。


6

そのため、すべての特定の要望を満たすために、リソースを元のツールの最適化にマーシャリングしませんでした。私たちが説明する必要があるのは、この特定の欲求を実装するのにどれだけのコストがかかるかです。

POSIXはユーティリティについて十分に定義しているので、異なる実装を持つことは問題のように思えません。

これは悪い仮定です:-P。

POSIX以降のシステムは、正当な理由により、より強力で便利になり続けています。事後基準として、実際に追いつくことはありません。

Ubuntuは、古いSystem V initブートプロセスを最適化するために、スクリプトを削除したPOSIXシェルに切り替える努力を開始しました。私はそれが失敗したと言っているわけではありませんが、クリーンアップする必要のある多くのバグを引き起こしました:「bashisms」、機能が利用可能であると/bin/sh仮定しながら実行されたスクリプトbash

POSIX shは、優れた汎用プログラミング言語ではありません。その主な目的は、対話型シェルとして機能することです。コマンドをスクリプトに保存し始めるとすぐに、Turing tarpitに近づくことに注意してください。たとえば、通常のパイプラインの途中で障害検出することはできません。 このためにbash追加されましたset -o pipefailが、これはPOSIXにはありません。

同様の便利だが標準化されていない機能は、ほとんどすべてのユーティリティよりも複雑ですtrue

概説するタスクのクラスについては、Awk、Perl、および最近のPythonに大まかな線を引くことができます。さまざまなツールが作成され、独立して進化しました。たとえば、GNU Awkがlibutilposixextendedに含まれると期待しますか?

私があなたに指摘できる普遍的に良いアプローチがあると言っているわけではありません。Pythonにはソフトスポットがあります。Awkは驚くほど強力ですが、GNU Awkに固有のいくつかの機能にイライラしていますが。しかし、ポイントは、(おそらくファイルの行から)多数の文字列を個別に処理することは、POSIXシェルの設計目標ではなかったことです。


シェルがコマンドに関するすべてを理解している場合、設定可能な場所のリストから実行されたコマンドはすべてビルトインとして扱われると想定するシェルに問題があるのでしょうか?スクリプトが実行cat -@fnord fooする場合、シェルは-@、実際のコマンドを呼び出す必要があることを意味しないためcat <foo >bar、シェルだけが別のプロセスを生成する必要がないことを決定する必要があります。
supercat

1
@supercatの複雑さ。
sourcejedi

2

また、次の質問もあります。どのシェルに組み込むか。

ほとんどのUnix / Linuxシステムには、独立して開発された複数の異なるシェルがあります(sh / bash / korn / ???)。ツールをシェルに組み込むと、シェルごとにこれらのツールの異なる実装が行われます。これによりオーバーヘッドが発生し、呼び出しに使用したシェルに応じて、grepなどで異なる機能/バグが発生する可能性があります。


zshは最近、一部のサークルで非常に人気があります。csh / tcshには歴史的に大きな支持がありましたが、今日はあまり見かけないと思います。そして、あまり知られていないシェルの全体の束が...あります
からCVn

モジュール性。ビルトインでは、これらのビルトインのいずれかに変更が加えられるたびに、シェルを再コンパイルまたは再インストールする必要があります。
can-ned_food

1

多くの人がよく答えました。私はそれらの答えをほめるだけです。UNIXの哲学は、ツールが1つのことを実行し、それをうまく実行する必要があると思います。すべてを網羅するツールを作成しようとすると、失敗する可能性が高くなります。このように機能を制限すると、信頼できるツールセットが作成されます。

また、sedgrepなどの機能がシェルに組み込まれている場合、必要なときにコマンドラインから簡単に呼び出すことができますか?

最後に、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のような機能が、中にパラメータ展開の下で見拡張ヘッダー同じmanページの。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.stackexchange.com
questions /

1

これは歴史的な事故だと思います。

1960年代後半から1970年代初頭にUNIXが作成されたとき、コンピューターには現在ほど多くのメモリがありませんでした。当時は、このすべての機能をシェルのビルトインとして実装することは可能でしたが、メモリの制限により、実装できる機能の量を制限するか、メモリ不足やスワップトラッシングのリスクを負う必要がありました。問題。

一方、特定の機能を個別のプログラムとして実装し、新しいプロセスをできるだけ軽く開始するために必要な2つのシステムコールを作成することにより、これらの問題がなく、妥当な速度で実行されるスクリプト環境を作成できます。速度。

もちろん、それらが別のプロセスとして実装されると、人々はシェルではないプログラムからそれらを開始し、その後はそのままにしておく必要があります。そうしないと、突然このソフトウェアがすべて壊れ始めます。

ただし、一部の機能を2回実装できないというわけではありません。実際、一部のシェルは、シェルビルトインとして外部プログラムとなるはずの機能を実装しています。たとえば、bash echoは組み込みコマンドとしてコマンドを実装しますが、/usr/bin/echo

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