似たような質問がたくさんありますが、私の質問に直接答える質問は見つかりません。オペレーティングシステムのメモリ管理、プロセス、プロセス間通信などの基本を理解します。ただし、パイプを介して入力を受け取ることができるコマンド実装と、コマンドパラメータのみを許可できるコマンド実装との基本的な違いは明らかではありません。
コマンドが1つの方法で入力を受け入れますが、他の方法では入力を許可しないのはなぜですか。
ls
簡単な例を挙げると、出力のファイル名をcat
表示用にパイプできますが、同じ操作を実行できないのはなぜですかrm
?これらの動作の違いをもたらす哲学的理由、深刻な技術的理由、または実装に任意の選択肢がありますか?
ls | cat
delete_me_1.txt
delete_me_2.txt
ls | rm
rm: missing operand
つまり、Linuxコマンドを作成する場合は、パイプ、コマンドパラメータ、またはその両方を介してコマンド入力を許可するかどうかを選択するためにどのような技術的要素を考慮する必要がありますか?
答え1
ただし、パイプを介して入力を受け取ることができるコマンド実装とコマンドパラメータのみを許可できるコマンド実装との基本的な違いは明らかではありません。
まあ、それらの1つ(またはその両方?)を使用するかどうかは、プログラム開発者が決定する問題です。オペレーティングシステムとは何の関係もなく、オペレーティングシステムが引数の渡し、入力ファイル記述子の読み取り、および読み取りメソッドを提供するだけです。標準入力レンダリング。
したがって、この質問はLinuxより20年以上前になるでしょう。これは、標準入力とコマンドライン引数の概念が最初に登場した時期です(Thompson、Ritchie、Kernigan、McIlroyが登場していないと確信しているUNIXの誕生)。意外にも)。
つまり、Linuxコマンドを作成する場合は、パイプ、コマンドパラメータ、またはその両方を介してコマンド入力を許可するかどうかを選択するためにどのような技術的要素を考慮する必要がありますか?
あなたの目的に合った可用性と適合性!
一部のデータを処理すると、より多くの可能性があります。効果がある特に、入力を生成したプログラムが終了する前に出力を生成できる場合は、標準入力として提供します。プログラムの起動時にのみコマンドライン引数を渡すことができるため、連続プロデューサを使用してデータストリーミングが必要な作業を実行する場合は、これを行う方法を疑問に思う必要はありません。
何かの動作を変更したり、可変数の引数に基づいて何かを計算したい場合は、その引数を入力に渡す構造化方法よりもコマンドライン引数を使用する方が簡単です。
だからそれは実際にあなたがどうするかによって異なります。考える使いたいプログラム。技術的な問題ではなく質問です。目的。
事実:今は2022年です。広く使用されている現代言語では、構造化入力データ(JSONなど)をプログラムで簡単に使用できる辞書/マップ/キー値データ構造に解析できるライブラリがあります。コマンドライン引数を解析する場合も同様です!一般に、コマンドライン引数パーサーは構成ファイルも構文解析できるため(CLI11などの標準入力を構成ファイルとして使用できます)、技術的にどちらかを実行できるプログラムを選択する必要さえありません。
答え2
コマンドが1つの方法による入力を許可しますが、他の方法による入力を許可しないのはなぜですか?
結局、プログラムはそのように作られるからだ。
より実質的には、プログラムは最も合理的な方法で入力を受け入れる傾向がある。入力がプログラムの動作を変更するファイル名またはオプションのセットである場合、これは通常コマンドラインで提供されます。通常、これはテキストで短いです。入力がデータの塊の場合はstdinを介して読み込みます。処理するデータはバイナリデータであり、長さが長くなる可能性があります。
たとえば、どちらもコマンドライン引数としてファイル名のリストをcat
使用します(どちらもオプションを使用できます)。また、コマンドラインでファイル名を受け入れることができますが、オプションも許可されており、その一部はそのファイルのデータに適用される実際の指示を指定することができます。それらはすべて指定されたファイルに対して機能します。内容を印刷、削除し、指定された方法で内容を処理します。rm
sed
cat
rm
sed
ファイル名が指定されていない場合は、両方ともデフォルトでsed
標準入力を読み込みます。cat
コマンドが許可する入力方法をどのように簡単に知ることができますか?
あなたはマニュアルを読んだ。あるいは、合理的な状況に基づいて推測してみてください。
ls
簡単な例を挙げると、出力のファイル名をcat
表示用にパイプできますが、同じ操作を実行できないのはなぜですかrm
?
cat
デフォルトでは、データストリームは標準入力から取得されるため、rm
ファイル名のリストのみがインポートされます。ちなみにls | cat
こうすればいいえ cat
リストされたファイル名に対しては機能しますが、リスト自体。ls
印刷して出力してもfoo.txt
出力になりますls |cat
foo.txt
cat foo.txt
コンテンツのfoo.txt
。ls * |cat
と同じではありませんcat *
。
オプションなしで通常のパイプを通過することはcat
データをそのまま渡すので、少し役に立ちません。使用する方がより合理的かもしれませんcat -n
。
はい、出力はls
基本的にテキストファイルと同様にデータストリームです。人の目にはファイル名のリストのように見えますが、実際には非常に難しいです。適切に人々が次の記事を書くようにしてください。https://mywiki.wooledge.org/ParsingLsそれに反対するために。この記事は何度もここにリンクされていましたが、これは非常に一般的な誤解です。 (はい、もちろん、xargs
データストリームをコマンドライン引数リストに変換するための同様のツールがありますが、うーん...ファイル名に改行が有効であることを覚えておいてください。)
これらの動作の違いをもたらす哲学的理由、深刻な技術的理由、または実装に任意の選択肢がありますか?
美しさは見る人の目にかかっているように聞こえますが、FWIW、私は実際の技術的な理由だけを見ます(上記参照)。
(*その他の場合:コマンドラインオプション()を使用して名前付きファイルsed
のコマンドを処理することもできます-f
。これは、Cプログラムをファイルに保存するのと同じようにスクリプトが長い場合に適しています。一部のプログラムは設定ファイルを読み込みます。一部の人が選択するコマンドラインオプションも意味があります。
答え3
木材を切断する機械を設計する場合、入力された数量は木材であると考えられ、切断厚さなどのパラメータは作業期間中に設定されます。
多くのデータ操作がこれらのたとえ話に関連しています。チェーン接続(パイピング)、並列化、展開など、さまざまな配列やアーキテクチャと連携します。このパラダイムは非常に柔軟で強力です。
wood > board 15cm | style moulding | transport | varnishing | transport > deposit
だから質問は「何」そして「何らかの方法で」まず答えを得てください。ジョブが任意に大量のデータを処理できる場合、これは入力でなければならず、他の情報は設定またはパラメーターです。
うまく設計されたプログラムはフィルタです。つまり、単にパイプを介して協力します。非常に一般的なプログラムsed, grep, awk, gzip, cat, md5sum, base64, bash, ssh
などが標準入力を読み取るように設計されていることがわかります。または、データ自体ではなくデータソースであるファイル名を引数として受け入れます。ファイル名はメタデータ、内容はデータです。
md5sum < /etc/crontab # don't care metadata
md5sum /etc/crontab # same result with metadata
rm
あいまいです。エントリを許可すると削除するパスになることができますが、パラメータとして保持する方が便利です。
とにかく、入力ストリームからパラメータに切り替える方法はいくつかあります。入力をパラメータに変換するときは、インタプリタの制限やその他の解析トラップ(引用符、区切り文字、置換)を考慮する必要があります。
ls | xargs -d'\n' rm # apply rm according to arg length limits
# NOT broken by spaces in filenames
# broken by newlines in filenames
ls | parallel -m rm # apply rm whith many parallel processes
# NOT broken by spaces in filenames
# broken by newlines in filenames
ls | while read;do rm "$REPLY";done # apply rm one by one
# NOT broken by spaces in filenames
# broken by newlines in filenames
ls | split -l1 --filter='read && rm "$REPLY"'
# why make it simple when you can make it complicated
rm $(ls) # apply rm all at once
# broken by arg length limit
# broken by space in filenames
rm * # apply rm all at once
# broken by arg length limit
# NOT broken by newline in filenames
(結論:問題が発生した場合は、ファイル名に改行を追加してください)
時には、ビジネスデータを扱うときに処理するデータの種類やその他のメタデータなど、データを特徴付けるいくつかの情報をパラメータに入力する傾向があります。メタデータと他のパラメータを区別するのは良い考えだと思います。マシンがメタデータを読み取って適応できる限り、メタデータはデータとともに自然に発生します。
例:
hard wood > board 15cm | style moulding | transport | varnishing | transport > deposit
この場合、オペレータに調整を確認させるのではなく、カッターとシェーパーが出力とブレードを調整できる場合は利点があります。
単一のデータストリームを構築するためにいくつかのメタデータとデータを結合する多くのプログラム例があります。
tar -cf- /etc | tar -tf-
最後に、広範囲に分散したビジネスワークフローでは特にトレーサビリティが必要であるため、特定のタスク(ローカルパラメータなど)に固有の情報と、入力、データ、メタデータに続く情報を明確に区別する必要があります。
もう1つ知っておくべきこと:パラメータはコマンドに公開されているので、ps
秘密パラメータでプログラムを設計することは非常に悪い考えです。代わりに間接入力方法を使用してください。