コメントリーダーにすぎないが、実際にはシェル自体が組み込まれているコマンドの目的は何ですか?
スクリプトにコメントを挿入するよりも呼び出しごとに約40%遅くなりますが、これはおそらくコメントのサイズによって大きく異なります。私がそれを見ることができる唯一の考えられる理由はこれらです:
# poor man's delay function
for ((x=0;x<100000;++x)) ; do : ; done
# inserting comments into string of commands
command ; command ; : we need a comment in here for some reason ; command
# an alias for `true' (lazy programming)
while : ; do command ; done
私が本当に探しているのは、それがどのような歴史的なアプリケーションだったのかと思います。
歴史的に、Bourneシェルには、組み込みコマンドとしてtrue
およびfalse
がありませんでした。代わりにtrue
は単に:
にエイリアスされ、false
はlet 0
のようなものにエイリアスされました。
:
は、古代のBourne派生シェルへの移植性のためにtrue
よりわずかに優れています。簡単な例として、!
パイプライン演算子も||
リスト演算子も使用しないことを検討してください(古代のBourneシェルの場合と同様)。これにより、else
ステートメントのif
句が、終了ステータスに基づいて分岐するための唯一の手段として残ります。
if command; then :; else ...; fi
if
には空でないthen
句が必要であり、コメントは空ではないとカウントされないため、:
はノーオペレーションとして機能します。
Nowadays(つまり、最新のコンテキストでは)通常、:
またはtrue
を使用できます。両方ともPOSIXで指定されており、一部はtrue
が読みやすくなっています。ただし、興味深い違いが1つあります。:
は、いわゆるPOSIX特殊なビルトインですが、true
はです通常の組み込み。
シェルに特別なビルトインを組み込む必要があります。通常のビルトインは「通常」のみビルトインされますが、厳密には保証されていません。通常、ほとんどのシステムのPATHにtrue
の機能を持つ:
という名前の通常のプログラムはありません。
おそらく最も重要な違いは、特殊なビルトインでは、ビルトインによって設定された変数は、単純なコマンド評価中の環境であっても、コマンドが完了した後も持続することです。
$ unset x; ( x=hi :; echo "$x" )
hi
$ ( x=hi true; echo "$x" )
$
Zshは、POSIX互換モードで動作する場合を除き、GNU Bashと同様にこの要件を無視しますが、他のすべての主要な「POSIX sh派生」シェルは、ダッシュ、ksh93、mkshを含むこれを監視します。
別の違いは、通常のビルトインはexec
と互換性がなければならないことです。ここでは、Bashを使用して説明します。
$ ( exec : )
-bash: exec: :: not found
$ ( exec true )
$
POSIXでは、:
がtrue
よりも高速である可能性があることも明示的に指摘していますが、これはもちろん実装固有の詳細です。
変数コマンドを簡単に有効/無効にするために使用します:
#!/bin/bash
if [[ "$VERBOSE" == "" || "$VERBOSE" == "0" ]]; then
vecho=":" # no "verbose echo"
else
vecho=echo # enable "verbose echo"
fi
$vecho "Verbose echo is ON"
かくして
$ ./vecho
$ VERBOSE=1 ./vecho
Verbose echo is ON
これにより、クリーンなスクリプトが作成されます。これは「#」では実行できません。
また、
: >afile
は、「afile」の存在を保証する最も簡単な方法の1つですが、長さは0です。
:の便利なアプリケーションは、結果を実際にコマンドに渡すのではなく、副作用のためにパラメーター展開を使用することにのみ関心がある場合です。その場合、0または1の終了ステータスが必要かどうかに応じて、PEを:またはfalseの引数として使用します。例として: "${var:=$1}"
があります。 :
は組み込み関数なので、かなり高速です。
:
は、ブロックコメント用にも使用できます(C言語の/ * * /と同様)。たとえば、スクリプト内のコードブロックをスキップする場合は、次の操作を実行できます。
: << 'SKIP'
your code block here
SKIP
ログをクリアするのに役立つファイルをゼロバイトに切り捨てたい場合は、これを試してください:
:> file.log
Pythonのpass
に似ています。
用途の1つは、記述されるまで関数をスタブすることです。
future_function () { :; }
他の回答で言及されていないさらに2つの用途:
次のスクリプト例をご覧ください。
set -x
: Logging message here
example_command
最初の行set -x
は、実行する前にシェルにコマンドを出力させます。これは非常に便利な構造です。欠点は、通常のecho Log message
タイプのステートメントがメッセージを2回出力するようになったことです。コロンメソッドはその周りを取得します。 echo
の場合と同様に、特殊文字をエスケープする必要があることに注意してください。
次のように、cronジョブで使用されるのを見てきました。
45 10 * * * : Backup for database ; /opt/backup.sh
これは、スクリプト/opt/backup.sh
を毎日10:45に実行するcronジョブです。この手法の利点は、/opt/backup.sh
が出力を出力するときに、電子メールの件名をより見やすくすることです。
これをバックティック(``
)と組み合わせて使用すると、次のように出力を表示せずにコマンドを実行できます。
: `some_command`
もちろん、some_command > /dev/null
を実行することもできますが、:
- versionは多少短くなります。
そうは言っても、人々を混乱させるだけなので、実際に行うことはお勧めしません。考えられるユースケースとして頭に浮かんだのです。
また、多言語プログラムにも役立ちます。
#!/usr/bin/env sh
':' //; exec "$(command -v node)" "$0" "$@"
~function(){ ... }
これは現在、実行可能なシェルスクリプトであるおよび JavaScriptプログラムです。つまり、./filename.js
、sh filename.js
、およびnode filename.js
はすべて機能します。
(間違いなく少し奇妙な使い方ですが、それでも効果的です。)
要求されたいくつかの説明:
シェルスクリプトは行ごとに評価されます。 exec
コマンドを実行すると、シェルが終了し、replacesが結果のコマンドで処理されます。つまり、シェルから見ると、プログラムは次のようになります。
#!/usr/bin/env sh
':' //; exec "$(command -v node)" "$0" "$@"
Wordでパラメーターの展開またはエイリアスが発生しない限り、anyシェルスクリプト内のWordは、その意味を変更せずに引用符で囲むことができます。これは、':'
が:
と同等であることを意味します(以下で説明するJavaScriptのセマンティクスを実現するために、ここでは引用符で囲んだだけです)
...上記のように、最初の行の最初のコマンドはノーオペレーションです(: //
に変換されます。または、単語を引用したい場合は':' '//'
になります。//
は、JavaScriptのようにここでは特別な意味を持ちません;それは捨てられている意味のないWordです。)
最後に、最初の行(セミコロンの後)の2番目のコマンドは、プログラムの本質です。それは、呼び出されるシェルスクリプトをNodeで置き換えるexec
呼び出しです。スクリプトの残りを評価するために呼び出される.jsプロセス。
一方、JavaScriptの最初の行は、文字列リテラル(':'
)として解析され、次にコメントが削除されます。したがって、JavaScriptにとって、プログラムは次のようになります。
':'
~function(){ ... }
文字列リテラルは単独で行にあるため、no-opステートメントであり、プログラムから削除されます。つまり、行全体が削除され、onlyがプログラムコード(この例ではfunction(){ ... }
本体)のままになります。
:
を使用して、ドキュメントを関数に埋め込むこともできます。
さまざまな機能を提供するライブラリスクリプトmylib.sh
があるとします。ライブラリをソース(. mylib.sh
)し、その直後に関数を呼び出す(lib_function1 arg1 arg2
)か、名前空間が乱雑になるのを避け、関数の引数でライブラリを呼び出す(mylib.sh lib_function1 arg1 arg2
)ことができます。
ヘルプテキストで関数リストを手動で管理しなくても、mylib.sh --help
と入力して使用可能な関数とその使用法のリストを取得できると便利です。
#!/ bin/bash #すべての「パブリック」機能は、このプレフィックスで開始する必要があります LIB_PREFIX = 'lib _' # "パブリック"ライブラリ関数 lib_function1(){ :この関数は、2つの引数で複雑な処理を行います。 : :パラメーター: : 'arg1-最初の引数($ 1)' : 'arg2-2番目の引数' : :結果: : "複雑です" #実際の関数コードはここから始まります } lib_function2(){ :関数のドキュメント #ここに関数コード } #help function -help(){ echo MyLib v0.0.1 echo echo使用法:mylib.sh [function_name [args]] echo echo利用可能な関数: declare -f | sed -n -e '/ ^' $ LIB_PREFIX '/、/ ^} $/{/ \(^' $ LIB_PREFIX '\)\ | \(^ [\ t] *:\)/ { s/^ \( '$ LIB_PREFIX'。* \)()/\n ===\1 === /; s/^ [\ t] *:\?['\' '"] \?//; s/['\' '"] \?; \?$ //; p}}' } #main code if [" $ {BASH_SOURCE [0]} "=" $ {0} "]; then #sourced の代わりにスクリプトが実行された#要求された機能を呼び出すか、ヘルプを表示 if ["$(type -t-" $ 1 "2>/dev/null) "=関数]; then "$ @" else --help fi fi
コードに関するいくつかのコメント:
declare -f
を使用して使用可能なすべての関数を列挙し、sedを介してそれらをフィルター処理して、適切なプレフィックスを持つ関数のみを表示します。mylib.sh function1
と入力するだけで、内部でlib_function1
に変換されます。これは読者に任せた演習です。$1
の追加チェックをコーディングする必要なく、ライブラリ呼び出しメカニズムを使用してヘルプ自体を表示する便利な(つまり、レイジー)アプローチです。同時に、ライブラリをソースにすると名前空間が乱雑になります。気に入らない場合は、名前をlib_help
のような名前に変更するか、実際にメインコードで--help
の引数を確認して、手動でヘルプ関数を呼び出すことができます。スクリプトでこの使用法を見ましたが、スクリプト内でbasenameを呼び出すのに適した方法だと思いました。
oldIFS=$IFS
IFS=/
for basetool in $0 ; do : ; done
IFS=$oldIFS
...これはコードの代替です:basetool=$(basename $0)