web-dev-qa-db-ja.com

bashのnoop [:]の使用例は何ですか?

Bash(:)でnoopを検索しましたが、良い情報を見つけることができませんでした。この演算子の正確な目的または使用例は何ですか?

私はフォローしようとしましたが、私にとってはこのように機能しています:

[mandy@root]$ a=11
[mandy@root]$ b=20
[mandy@root]$ c=30
[mandy@root]$ echo $a; : echo $b ; echo $c
10
30

リアルタイムでのこの演算子の使用事例、またはそれを使用することが義務付けられている場所をお知らせください。

103
Mandar Pande

歴史的な理由により多くあります。コロンの組み込み:は、trueとまったく同じです。戻り値が重要な場合、たとえば無限ループでtrueを使用するのが伝統的です。

while true; do
  echo 'Going on forever'
done

シェルの構文にコマンドが必要だが、何もする必要がない場合、:を使用するのが伝統的です。

while keep_waiting; do
  : # busy-wait
done

:ビルトインは Thompson Shell にまでさかのぼり、 nix v6 では present でした。 :は、Thompson Shellのgotoステートメントのラベルインジケーターでした。ラベルは任意のテキストにすることができるため、:はコメントインジケータとして2重になります(goto commentがない場合、: commentは事実上コメントです)。 Bourne Shell にはgotoがありませんでしたが、:は保持されました。

:を使用する一般的なイディオムは : ${var=VALUE} です。これは、varが未設定の場合はVALUEに設定し、varの場合は何も行いませんすでに設定されていました。このコンストラクトは変数置換の形式でのみ存在し、この変数置換は何らかの形でコマンドの一部である必要があります:no-opコマンドはうまく機能します。

コロンビルトインはどのような目的で機能しますか? も参照してください。

150
Gilles

すべてのコードをコメントアウトするときのifステートメントに使用します。たとえば、テストがあります:

if [ "$foo" != "1" ]
then
    echo Success
fi

ただし、次のものに含まれるすべてを一時的にコメントアウトする必要があります。

if [ "$foo" != "1" ]
then
    #echo Success
fi

これにより、bashで構文エラーが発生します。

line 4: syntax error near unexpected token `fi'
line 4: `fi'

Bashは空のブロック(WTF)を持つことはできません。そのため、no-opを追加します。

if [ "$foo" != "1" ]
then
    #echo Success
    :
fi

または、no-opを使用して行をコメントアウトできます。

if [ "$foo" != "1" ]
then
    : echo Success
fi
14

:を使用して、成功するが何もしないコマンドを提供します。この例では、「verbosity」コマンドはデフォルトでオフになっており、:に設定されています。 「v」オプションはそれをオンにします。

#!/bin/sh
# example
verbosity=:                         
while getopts v OPT ; do          
   case $OPT in                  
       v)        
           verbosity=/bin/realpath 
       ;;
       *)
           exit "Cancelled"
       ;;             
   esac                          
done                              

# `$verbosity` always succeeds by default, but does nothing.                              
for i in * ; do                   
  echo $i $($verbosity $i)         
done                              

$ example
   file

$ example -v
   file /home/me/file  
7
Mark

set- eを使用する場合、|| :notが失敗した場合にスクリプトを終了するための優れた方法です(明示的にパスします)。

7
Crisfole

alias引数を無視

引数を取らないエイリアスが必要な場合があります。 :を使用して実行できます:

> alias alert_with_args='echo hello there'

> alias alert='echo hello there;:'

> alert_with_args blabla
hello there blabla

> alert blabla
hello there
5
Ulysse BN

1つの用途は、複数行のコメントとして、またはコードをhereファイルと組み合わせて使用​​して、テスト目的でコードの一部をコメントアウトすることです。

_: << 'EOF'

This part of the script is a commented out

EOF
_

EOFを引用符で囲むことを忘れないでください。そうすれば、$(foo)のように内部のコードが評価されません。また、NOTESSCRATCHPAD、またはTODOなどの直感的なターミネーター名を使用する価値があります。

4

私の2つ。

PODコメントを埋め込む

:の非常にファンキーなアプリケーションは、 bashスクリプトにPODコメントを埋め込む のためです。そのため、manページをすばやく生成できます。もちろん、最終的にはPerlでスクリプト全体を書き直します;-)

実行時関数バインディング

これは、実行時に関数をバインドするための一種のコードパターンです。 F.i.、特定のフラグが設定されている場合にのみ何かを行うデバッグ機能があります:

#!/bin/bash
# noop-demo.sh 
shopt -s expand_aliases

dbg=${DBG:-''}

function _log_dbg {
    echo >&2 "[DBG] $@"
}

log_dbg_hook=':'

[ "$dbg" ] && log_dbg_hook='_log_dbg'

alias log_dbg=$log_dbg_hook


echo "Testing noop alias..."
log_dbg 'foo' 'bar'

あなたが得る:

$ ./noop-demo.sh 
Testing noop alias...
$ DBG=1 ./noop-demo.sh 
Testing noop alias...
[DBG] foo bar
3
sphakka

No-op句を使用すると、コードが読みやすくなる場合があります。

それは意見の問題かもしれませんが、ここに例があります。 2つのUNIXパスを使用して機能する関数を作成したとします。あるパスから別のパスにcdするのに必要な「パスの変更」を計算します。パスは両方とも「/」で開始する必要があるという制限を関数に設定しますOR両方ではいけません。

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        true      # continue with function
    else
        return 1  # Skip function.
    fi

一部の開発者はno-opを削除したいと思うでしょうが、それは条件を否定することを意味します:

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" != / || "$fromC" == / ]] && [[ "$toC" == / || "$fromC" != / ]]
    then
        return 1  # Skip function.
    fi

さて、私の意見では、関数の実行をスキップする条件がif句からそれほど明確ではありません。 no-opを排除して明確に行うには、関数からif節を移動する必要があります。

    if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        cdPath=$(chgPath pathA pathB)   # (we moved the conditional outside)

良く見えますが、多くの場合、これを行うことはできません。関数内でチェックを実行する必要があります。

では、これはどのくらいの頻度で発生しますか?それほど頻繁ではありません。たぶん年に1、2回。頻繁に発生するため、注意してください。 (言語に関係なく)コードの可読性が向上すると思うとき、私はそれを使うことをためらいません。

2
Bitdiot

この回答 に多少関連しているため、このno-opは polyglot スクリプトをハッキングするのにかなり便利です。たとえば、bashとvimscriptの両方に有効なコメントを次に示します。

":" #    this is a comment
":" #    in bash, ‘:’ is a no-op and ‘#’ starts a comment line
":" #    in vimscript, ‘"’ starts a comment line

もちろん、trueも使用したかもしれませんが、:句読点記号であり、無関係な英語の単語ではないことは、それが構文トークンであることを明確にします。


whyについては、誰かがポリグロットスクリプトを書くなどのトリッキーなことをするでしょう(クールであることに加えて):それは、ファイルXはファイルYを参照しています。

そのような状況では、両方のスクリプトを単一のポリグロットファイルに組み合わせることで、Xへのパスを決定するためのYでの作業が回避されます(単に"$0")。さらに重要なことは、プログラムの移動や配布がより便利になることです。

  • 一般的な例。シェバンにはよく知られた長年の問題があります:ほとんどのシステム(LinuxとCygwinを含む)はone引数のみを許可します通訳者に渡されます。次のシバン:

    #!/usr/bin/env interpreter --load-libA --load-libB
    

    次のコマンドを実行します。

    /usr/bin/env "interpreter --load-libA --load-libB" "/path/to/script"
    

    意図したものではありません:

    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"
    

    したがって、次のようなラッパースクリプトを作成することになります。

    #!/usr/bin/env sh
    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"
    

    これは多舌症が舞台に入る場所です。

  • より具体的な例。かつてVimを起動するbashスクリプトを書いたことがあります。 Vimに追加のセットアップを行う必要がありました。これは、オプション--cmd "arbitrary vimscript command here"。ただし、そのセットアップはかなりのものであったため、文字列でインライン化するのはひどいことでした(可能な場合)。したがって、より良い解決策は、構成ファイルにin extensoと記述し、Vimに-S "/path/to/file"。したがって、ポリグロットbash/vimscriptファイルになりました。

2
Maëlan

別の成功に連鎖させたいコマンドがあるとします:

cmd="some command..."
$cmd
[ $? -eq 0 ] && some-other-command

ただし、条件付きでコマンドを実行し、実行されるコマンドを表示したい場合(dry-run):

cmd="some command..."
[ ! -z "$DEBUG" ] && echo $cmd
[ -z "$NOEXEC" ] && $cmd
[ $? -eq 0 ] && {
    cmd="some-other-command"
    [ ! -z "$DEBUG" ] && echo $cmd
    [ -z "$NOEXEC" ] && $cmd
}

したがって、DEBUGとNOEXECを設定すると、2番目のコマンドは表示されません。これは、最初のコマンドは実行されないため(NOEXECが空ではないため)、その事実を評価すると1が返されるため、下位コマンドは実行されないことを意味します(ただし、ドライランであるため実行したい)。これを修正するには、スタックに残っている終了値をnoopでリセットできます。

[ -z "$NOEXEC" ] && $cmd || :
0
ekkis