Unixシェルの「stdin / stdout API」はどれくらい安定していますか?


20

grepping、awking、sedding、pipingは、Unixライクなオペレーティングシステムのユーザーの日常的なルーチンであり、コマンドラインまたはシェルスクリプト(以降、総称してフィルターと呼ばれます)内にあります。

本質的に、「標準」のUnix CLIプログラムとシェルビルトイン(これ以降コマンドと総称される)を使用する場合、フィルターは正しく機能するために各フィルターステップでstdin、stdout、およびstderrの正確な予測形式を必要とします。以下では、このコマンドのこの正確な形式をこのコマンドのAPIと呼びます。

Web開発のバックグラウンドを持つ人として、この種のデータ収集とデータ処理を技術的にWebスクレイピングと比較します。これは、データ表示にわずかな変化がある場合でも非常に不安定な手法です。

私の質問は、UnixコマンドAPIの安定性に関するものです。

  1. Unixライクなオペレーティングシステムのコマンドは、入力と出力に関して正式な標準化に従っていますか?
  2. いくつかの重要なコマンドの更新が、古いバージョンのコマンドを使用して作成されたフィルターの機能を破壊する原因となったことがありますか?
  3. Unixコマンドは、あるフィルターが壊れるような方法で変更することは絶対に不可能であるという時間の経過とともに成熟しましたか?
  4. コマンドAPIの変更によりフィルターが時々破損する可能性がある場合、開発者としてフィルターをこの問題から保護するにはどうすればよいですか?

回答:


17

POSIX 2008標準には、「シェルとユーティリティ」を説明するセクションがあります。一般的に、スクリプトを廃止する場合を除き、スクリプトはかなり将来性があるはずですが、一晩でほとんど発生しないため、スクリプトを更新するための十分な時間が必要です。

単一のユーティリティの出力形式がプラットフォームやバージョンによって大きく異なる場合、POSIX標準には、通常呼び出される、-pまたは-P保証された予測可能な出力形式を指定するオプションが含まれる場合があります。この例として、timeユーティリティがあります。これにはさまざまな実装があります。安定したAPI /出力形式が必要な場合は、を使用しますtime -p

POSIX標準でカバーされていないフィルターユーティリティを使用する必要がある場合は、Webスクレイピングを行うときにリモートWeb開発者に任せているのと同じように、ディストリビューションパッケージャー/アップストリーム開発者に任せています。


12

私の経験から答えようとします。

  1. コマンドは実際には正式な仕様に準拠していませんが、行指向のテキストを消費および生成する要件に準拠しています。

  2. はい、もちろん。GNUユーティリティが事実上の標準になる前に、多くのベンダーは、特にとに関して、風変わりな出力をpsしていましたls。これは多くの痛みを引き起こしました。現在、HPだけが非常に奇妙なコマンドを提供しています。歴史的に、Berkeley Software Distribution(BSD)ユーティリティは過去との大きな隔たりでした。POSIX仕様は過去からの脱却でしたが、今では広く受け入れられています。

  3. Unixコマンドは確かに時間の経過とともに成熟しました。古いバージョン用に書かれたスクリプトを破ることはまだ不可能ではありません。テキストファイルエンコーディングとしてのUTF-8への最近の傾向を考えてください。この変更により、などの基本的なユーティリティを変更する必要がありましたtr。過去には、単純なテキストはほとんど常にASCII(またはそれに近いもの)だったため、小文字と同様に大文字が数値範囲を形成していました。これはUTF-8では当てはまらないため、tr「大文字」や「英数字」などを指定するさまざまなコマンドラインオプションを受け入れることができます。

  4. フィルタを「堅牢化」する最良の方法の1つは、特定のテキストレイアウトに依存しないことです。たとえばcut -c10-24、行の位置に依存するdoしないでください。cut -f2代わりに使用します。これにより、2番目のタブ区切りフィールドが切り取られます。 awk入力行をデフォルトで空白で区切られた$ 1、$ 2、$ 3 ...に分割します。列の位置などの下位レベルの概念ではなく、「フィールド」などの上位レベルの概念に依存します。また、正規表現を使用しますsedし、awk両方の入力中にいくつかの差異を気にしない正規表現で物事を行うことができます。もう1つの方法は、入力を処理して、フィルターが扱いにくい形式に変換することです。tr -cs '[a-zA-z0-9]' '[\n]'句読点なしで、テキストを1行につき1つの単語に分割するために使用します。あなたはただ


9

最初に、あなたの質問に対する非常に短い答え:

  1. 入出力規則の正式な標準化:なし
  2. 出力の変更による過去の破損:はい
  3. 将来のフィルターを破ることは絶対に不可能です:いいえ
  4. どうすれば変更から身を守ることができますか:保守的になります

「API」と言うときは、フィルタの入力/出力規則に関する形式が多すぎることを暗示する用語を使用しています。非常に(そして、私は「非常に」という意味です)広義には、簡単なフィルタリングに馴染みやすいデータの主な規則は

  • 各入力行は完全なレコードです
  • 各レコード内で、フィールドは既知の区切り文字で区切られます

典型的な例は、/ etc / passwdの形式です。しかし、これらのデフォルトの規則は、おそらく手紙に従うよりもある程度頻繁に違反されます。

  • 複数行の入力形式を解析する多くのフィルター(多くの場合awkまたはperlで記述されています)があります。
  • 明確に定義されたフィールド構造がない入力パターン(/ var / log / messagesなど)が多数あり、より一般的な正規表現ベースの手法を使用する必要があります。

4番目の質問である、出力構造の変動から身を守る方法は、本当にあなたが何でもできる唯一の質問です。

  • 以下のようjw013 @語っ POSIX標準の言うことを見て、。もちろん、posixは、入力ソースとして使用するすべてのコマンドを指定するわけではありません。
  • スクリプトを移植可能にしたい場合は、たまたま何らかのコマンドを実行した場合のバージョンの特異性を避けるようにしてください。たとえば、標準のUNIXコマンドの多くのGNUバージョンには、非標準の拡張機能があります。これらは役に立つかもしれませんが、最大限の移植性が必要な場合は避けるべきです。
  • コマンドの引数のサブセットと出力形式がプラットフォーム間で安定している傾向があることを学習してください。残念ながら、これには時間とともに複数のプラットフォームにアクセスする必要があります。これらの違いは、非公式にさえどこにも書き留められないからです。

最終的には、心配している問題から完全に保護することはできません。また、特定のコマンドが何をすべきかについての「決定的な」ステートメントを探す唯一の場所はありません。多くのシェルスクリプト、特に個人用または小規模な使用のために記述されたスクリプトでは、これは単に問題ではありません


5

あなたの質問の1)のみをカバーしています。

当然のことながら、APIは作成者の意思で常に変更される可能性があり、したがって、どの言語の依存ソフトウェアも破損する可能性があります。そうは言っても、UnixツールのI / O "API" の素晴らしいアイデアは、実際には何もない(おそらく0x0a行末として)ということです。優れたスクリプトは、データを作成する代わりにUnixツールでフィルタリングします。つまり、入力または出力の仕様が変更されたためにスクリプトが破損する可能性がありますが、スクリプトで使用される個々のツールのI / O形式(実際には1つではない)が変更されたためではありません(実際には存在しないため)本当に変えることはできません)。

基本的なツールのリストに目を通すと、フィルターだけではなく、producerの属性もあります。

  • wc-バイト数、ワード数、行数を出力します- 非常に単純な形式であり、変更される可能性はまったくなく、さらにスクリプトで使用される可能性も非常に低いです。
  • diff-さまざまな出力形式が進化していますが、問題は聞いていません。また、監督なしでは通常使用されません。
  • 日付 -今ここに私たちは本当に、特にシステムのロケールについて、私たちが生産何世話をする必要があります。ただし、それ以外の場合は、出力形式を自分で正確に指定しないと、RFCに準拠します。
  • cal-それについては話さずに、出力フォーマットがシステム間で大きく異なることを知っています。
  • lswhowlast -lsを解析したいのなら仕方がありません。意図したものではありません。また、最後に、誰がよりインタラクティブなリスターです。スクリプトでそれらを使用する場合は、何をするかに注意する必要があります。
  • 別の投稿で時間が指摘されました。しかし、ええ、それはlsと同じです。インタラクティブ/ローカルでの使用向け。また、bashビルトインはGNUバージョンとは大きく異なり、GNUバージョンには長年修正されていないバグがあります。それに頼らないでください。

バイトストリームであるよりも特定の入力形式を期待するツールは次のとおりです。

  • bcdc-電卓。すでによりハック的な側面で(実際、スクリプトでは使用していません)、おそらく非常に安定したI / O形式です。

破損のリスクがはるかに高い別の領域、つまりコマンドラインインターフェイスがあります。ほとんどのツールには、システム間およびタイムライン全体で異なる機能があります。例は

  • 正規表現を使用するすべてのツール -正規表現は、システムロケール(LC_COLLATEなど)に基づいて意味を変更でき、正規表現の実装には多くの微妙さと特徴があります。
  • 派手なスイッチを使用しないでください。man 1p findたとえば、システムのマンページの代わりにPOSIX検索のマンページを読むために簡単に使用できます。私のシステムには、manpages-posixがインストールされている必要があります。

そして、そのようなスイッチを使用していても、通常は微妙にエラーが発生することはなく、データを汚染します。ほとんどのプログラムは、未知のスイッチでの動作を単に拒否します。

結論として、シェルは実際には最も移植性の高い言語の1つになる可能性があると言えます(移植性のあるスクリプトを作成すると、シェルは移植可能になります)。微妙なエラーが発生するお気に入りのスクリプト言語、またはコンパイルを放棄するお気に入りのコンパイル済みプログラムと比較してください。

さらに、非互換性のために破損が発生する可能性のあるまれな場所では、おそらく誘導された時間ではなく、異なるシステム全体の多様性のためです(つまり、あなたのために働くなら、それは20年前と20年後にそうなりました) 、も)。これは、ツールのシンプルさの結果です。


1

事実上のIO標準だけがあります—ホワイトスペースとnullで区切られた出力です。

互換性に関しては、通常、個々のフィルターのバージョン番号のチェックに戻ります。それらが大きく変わるわけではありませんが、新しい機能を使用し、それでも古いバージョンでスクリプトを実行したい場合は、何らかの形で「ifdef」する必要があります。手動でテストケースを作成する場合を除き、機能報告メカニズムは実質的にありません。


0

スクリプトは、他のスクリプトよりも頻繁に壊れます。古くて有名なソフトウェアは比較的同じままである傾向があり、とにかくそれが変わるとき互換性フラグをしばしば持っています。

あるシステムで記述されたスクリプトは動作し続ける傾向がありますが、多くの場合、別のシステムを破壊します。

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