grepping、awking、sedding、pipingは、コマンドラインやシェルスクリプト(総称してフィルター今後)。
本質的には、「標準」のUnix CLIプログラムとシェル組み込み関数(総称してコマンド今後、フィルターが正しく動作するためには、フィルターの各ステップで stdin、stdout、stderr の正確な想定フォーマットが必要になります。以下では、この特定のコマンドの正確な想定フォーマットを、このコマンドの API と呼びます。
ウェブ開発の経験がある者として、この種のデータ収集とデータ処理を技術的に比較すると、ウェブスクレイピング- データの表現に少しでも変化があると非常に不安定になる手法です。
私の質問は、Unix コマンド API の安定性に関するものです。
- Unix 系オペレーティング システムのコマンドは、入力と出力に関して正式な標準化に準拠していますか?
- これまで、重要なコマンドを更新したために、そのコマンドの古いバージョンを使用して構築されたフィルターの機能が壊れたという例がありましたか?
- Unix コマンドは時間の経過とともに成熟し、何らかのフィルターが壊れるような変更が絶対に不可能になったのでしょうか?
- コマンド API の変更によりフィルターが時々壊れる場合、開発者としてこの問題からフィルターを保護するにはどうすればよいでしょうか?
答え1
POSIX 2008標準には、「シェルとユーティリティ」一般に、これに従えば、スクリプトは将来にわたっても問題なく機能するはずです (ただし、廃止予定は一夜にして発生することはほとんどないため、スクリプトを更新する時間は十分にあります)。
単一のユーティリティの出力形式がプラットフォームやバージョンによって大きく異なる場合、POSIX標準には、保証された予測可能な出力形式を指定する-p
、またはと呼ばれるオプションが含まれることがあります-P
。その一例は、time
ユーティリティ、実装は多岐にわたります。安定した API/出力形式が必要な場合は、 を使用しますtime -p
。
POSIX 標準でカバーされていないフィルター ユーティリティを使用する必要がある場合、Web スクレイピングを行うときにリモート Web 開発者に左右されるのと同じように、ディストリビューション パッケージ作成者やアップストリーム開発者に左右されることになります。
答え2
私の経験からお答えしたいと思います。
コマンドは正式な仕様には準拠していませんが、行指向のテキストを消費および生成するという要件には準拠しています。
はい、もちろんです。GNU ユーティリティが事実上の標準になる前は、多くのベンダーが、特に と に関して奇妙な出力をしていました
ps
。ls
これは大きな問題でした。今日では、非常に奇妙なコマンドを提供しているのは HP だけです。歴史的に、Berkeley Software Distribution (BSD) ユーティリティは過去との大きな決別でした。POSIX 仕様は過去との決別でしたが、現在では広く受け入れられています。Unix コマンドは、確かに時間の経過とともに成熟してきました。古いバージョン用に書かれたスクリプトを壊すことは、まだ不可能ではありません。テキスト ファイルのエンコードとして UTF-8 を使用する最近の傾向について考えてみましょう。この変更により、 などの基本ユーティリティを変更する必要がありました
tr
。以前は、単純なテキストはほぼ常に ASCII (またはそれに近いもの) であったため、大文字は小文字と同様に数値の範囲を形成していました。これは UTF-8 では当てはまらなくなり、 はtr
「大文字」や「英数字」などを指定するためのさまざまなコマンド ライン オプションを受け入れるようになりました。フィルターを「堅牢にする」最も良い方法の 1 つは、特定のテキスト レイアウトに依存しないことです。たとえば、
cut -c10-24
行の位置に依存する を使用しないでください。cut -f2
代わりに を使用します。これは、2 番目のタブ区切りフィールドを切り捨てます。awk
は、入力行を $1、$2、$3... に分割します。これらは、既定では空白で区切られます。 は、列の位置などの低レベルの概念ではなく、「フィールド」などの高レベルの概念に依存します。また、正規表現を使用します。 と はsed
どちらawk
も、入力の多少の変化を気にしない正規表現で処理できます。もう 1 つのトリックは、フィルターがうるさい形式に入力を処理することです。 を使用して、tr -cs '[a-zA-z0-9]' '[\n]'
句読点なしでテキストを 1 行に 1 つの単語に分割します。その場合、入力テキストがどのようなものかは気にしません。
答え3
まず、あなたの質問に簡単に答えます。
- 入出力規則の正式な標準化:いいえ
- 出力の変更による過去の破損:はい
- 将来のフィルターを破ることは絶対に不可能です。いいえ
- 変更から身を守るにはどうすればいいですか?保守的になる
「API」という表現は、(良くも悪くも)フィルタの入力/出力規則に関する形式主義を暗示しています。非常に(本当に「非常に」という意味です)広義に言えば、簡単にフィルタリングできるデータの主な規則は次のとおりです。
- 各入力行は完全なレコードである
- 各レコード内では、フィールドは既知の区切り文字で区切られています。
典型的な例としては、/etc/passwd の形式が挙げられます。ただし、これらのデフォルトの規則は、厳密に遵守されるよりも、ある程度違反されることの方が多いと思われます。
- 複数行の入力形式を解析するフィルター (多くの場合、awk または perl で記述) は多数あります。
- 明確に定義されたフィールド構造がない入力パターン (例: /var/log/messages) が多数あり、より一般的な正規表現ベースの手法を使用する必要があります。
4 番目の質問、「出力構造の変動から自分自身を保護する方法」は、実際に対処できる唯一の質問です。
- として@jw013 は言ったPOSIX 標準が何を言っているか見てみましょう。もちろん、POSIX では入力ソースとして使用したいすべてのコマンドが指定されているわけではありません。
- スクリプトを移植可能にしたい場合は、インストールされているコマンドのバージョンの特異性を避けるようにしてください。たとえば、標準の UNIX コマンドの多くの GNU バージョンには、非標準の拡張機能があります。これらは便利な場合もありますが、移植性を最大限に高めたい場合は避けてください。
- コマンド引数と出力形式のどのサブセットがプラットフォーム間で安定しているかを学習してください。残念ながら、これらの違いは非公式であってもどこにも書き留められていないため、これには複数のプラットフォームへのアクセスと時間が必要です。
結局のところ、心配している問題から完全に身を守ることはできませんし、特定のコマンドが何をすべきかについての「決定的な」説明を頼りにできる場所もありません。多くのシェルスクリプト、特に個人または小規模な使用のために書かれたものにとって、これはまったく問題ではありません。
答え4
事実上の IO 標準は、空白と null で区切られた出力のみです。
互換性に関しては、通常は個々のフィルターのバージョン番号をチェックすることになります。バージョン番号はそれほど変更されませんが、まったく新しい機能を使用したい場合、スクリプトを古いバージョンで実行したい場合は、何らかの方法で「ifdef」で除外する必要があります。テスト ケースを手動で記述する以外に、機能レポート メカニズムは実質的に存在しません。