明示的に何も実行しない場合、シェルスクリプトの:コマンドのユーティリティは何ですか?


27

シェルスクリプトのコメントに関するこの質問への回答では、:が明示的に何もしない(ただし、コメントには使用されない)nullコマンドであることが示されています。

まったく何もしないコマンドのユーティリティは何でしょうか?



2
参照してくださいこの質問より良い答えを持ってここに、すなわち、その:ことが要求されるビルトイン、しながら、true変数のスコープに影響を与える、ではありません
旧Proの

2
優雅に明示的に何もしません。
mikeserv

回答:


19

通常true、ループで使用します。私はそれがより明確だと思う:

while true; do
    ...
done

私が見つけた:本当に便利な場所は、caseステートメントの場合です。何かに一致する必要があるが、実際には何もしたくない場合です。例えば:

case $answer in
    ([Yy]*) : ok ;;
    (*)     echo "stop."; exit 1 ;;
esac

3
同意する。 true条件の場合:、NOPの場合。
jw013

1
bashは受け入れますcase a in a ) ;; esac。これを受け入れないシェルはありますか?
カズ

@Kazは:によるPOSIXシェル文法case ${var} in value);; *) do_something;; esac許容可能です。:コマンドが空の場合には必要ありません。
リチャードハンセン

12

もともとは、Cコンパイルされたプログラムではなく、Bourneシェルプログラムであると判断するために使用されていました。これは、シバンと複数のスクリプト言語(csh、perl)の前でした。ちょうどで始まるスクリプトを実行できます:

$ echo : > /tmp/xyzzy
$ chmod +x /tmp/xyzzy
$ ./xyzzy

通常、スクリプトを$SHELL(または/bin/sh)に対して実行します。

それ以降、主な用途は引数を評価することです。私はまだ使用しています:

: ${EDITOR:=vim}

スクリプトでデフォルト値を設定します。


11

: 内部から終了しなければならないループを書くのに便利です。

while :
do
    ...stuff...
done

breakまたはexitが呼び出されない限り、またはシェルが終了シグナルを受信しない限り、これは永久に実行されます。


3
私はそれを感じるwhile true; do ...; doneよりも優れたリーダーと通信の意図をwhile :; do ...; done
リチャード・ハンセン

9

シェルスクリプトで「unless」ステートメントが必要な場合は、「not」条件を使用します。これは、一部のテストで間抜けに見えるか、true-clauseで「:」を使用し、実際のコードをfalse-句。

if [ some-exotic-condition ]
then
    :
else
    # Real code here
fi

「エキゾチックな状態」は、否定したくないものである可能性があります。または、「負の論理」を使用しない場合、それははるかに明確になります。


1
また、条件を逆にする方法を見つけるよりも、空のブランチにautoconfデフォルトを追加する方がはるかに簡単であるため、によって生成されたスクリプトにも表示され:ます。
ディートリッヒEpp

2
!前に貼り付けるの[ some-exotic-condition ]が間抜けであるかどうかはわかりませんが、: else間抜けではないので余分です。
カズ

@Kazには良い点があります。エキゾチックな条件を思い付くのは、せいぜい難しいことです。すべてを無効にする必要がある場合、それは1つのことですが、それによって条件が明確にならない場合があります。ありません '!' 条件全体を否定しますか、それとも最初の用語だけですか?時々「:」の真の句を持つことが最善です。
ブルースエディガー

!トークンは、コマンド全体のパイプ要素を否定します。 while ! grep ... ; do ... done またはif ! [ ... ] ; then ... fi。基本的にはtest/[]構文の外部にあります。参照:pubs.opengroup.org/onlinepubs/9699919799/utilities/…–
カズ

5

コマンドの空のシーケンスを許可しないというシェル文法の欠陥のために、行をコメントアウトすると構文エラーが発生する状況で、行を一時的にコメントアウトするために#文字に加えてこれを使用したことがあります:

if condition ; then
    :# temporarily commented out command
fi

:がない場合、コマンドシーケンスが欠落しています。これは構文エラーです。


4

私が:役に立つと思う2つのケースがあります:

デフォルトの変数割り当て

#!/bin/sh

# set VAR to "default value" if not already set in the environment
: "${VAR=default value}"

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR}"

これは、シェルスクリプトのユーザーがスクリプトを編集せずに設定を上書きできるようにする便利な方法です。(ただし、エクスポートされた環境でユーザーが使用する変数を偶然に持っている場合、予期しない動作のリスクを実行しないため、コマンドライン引数の方が優れています。)ユーザーが設定をオーバーライドする方法は次のとおりです。

VAR="other value" ./script

${VAR=value}構文はセットに言うVARvalueあればVAR、既に設定されていない場合、変数の値に展開されます。変数の値はまだ気にしないので、それ:を捨てるためにno-opコマンドに引数として渡されます。

にもかかわらず:、展開はシェルによって行われる(ないノーオペレーションコマンドで:実行する前に、コマンド!) :(該当する場合)変数の割り当てが依然として発生してコマンドが。

true代わりにを使用したり、他のコマンドを使用したりすることもでき:ますが、意図が明確でないため、コードが読みにくくなります。

次のスクリプトも機能します。

#!/bin/sh

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR=default value}"

しかし、上記の維持ははるかに困難です。を使用する行${VAR}がそのprintf行の上に追加された場合、デフォルトの割り当て展開を移動する必要があります。開発者がその割り当てを移動するのを忘れると、バグが発生します。

空の条件ブロックに入れるもの

空の条件ブロックは一般に回避する必要がありますが、役に立つ場合があります。

if some_condition; then
    # todo:  implement this block of code; for now do nothing.
    # the colon below is a no-op to prevent syntax errors
    :
fi

空のtrue ifブロックがあると、テストを無効にするよりもコードが読みやすくなると主張する人もいます。例えば:

if [ -f foo ] && bar || baz; then
    :
else
    do_something_here
fi

間違いなく読みやすい:

if ! [ -f foo ] || ! bar && ! baz; then
    do_something_here
fi

ただし、空の真のブロックよりも優れた代替アプローチがいくつかあると考えています。

  1. 関数に条件を入れます:

    exotic_condition() { [ -f foo ] && bar || baz; }
    
    if ! exotic_condition; then
        do_something_here
    fi
  2. 否定する前に、条件を中括弧(または括弧、ただし括弧はサブシェルプロセスを生成し、サブシェル内の環境に加えられた変更はサブシェルの外側に表示されません)に入れます。

    if ! { [ -f foo ] && bar || baz; } then
        do_something_here
    fi
  3. ||代わりに使用if

    [ -f foo ] && bar || baz || {
        do_something_here
    }

    反応が条件をアサートするような単純なワンライナーである場合、私はこのアプローチを好みます:

    log() { printf '%s\n' "$*"; }
    error() { log "ERROR: $*" >&2; }
    fatal() { error "$@"; exit 1; }
    
    [ -f foo ] && bar || baz || fatal "condition not met"

1

UNIXの古代バージョンの古いpre-bourneシェルでは、:コマンドは元々ラベルを指定するためのgotoものでした(ラベルが見つかった場所に入力を巻き付ける別個のコマンドであったため、labelsはshell ifは、別のコマンドでもありました。)コメント構文(#バックスペースに使用されていました)が登場する前に、すぐにコメントに使用されるようになりました。


0

何もしないステートメントとして使用することに加えて、それを使用して、単一のステートメントを:の引数に変換することでコメントアウトできます。


: echo write this line > myfile空のファイルが作成されるため、コメントにはなりません。
アルケージュ

5
質問のリンクで説明されているように、適切なコメントメカニズムで:はありません
jw013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.