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


123

bash(:)でnoopを検索しましたが、適切な情報を見つけることができませんでした。このオペレーターの正確な目的またはユースケースは何ですか?

私は以下を試してみましたが、それは私にとってはこのように機能しています:

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

このオペレーターの使用例をリアルタイムで、または使用が義務付けられている場所に教えてください。



:組み込みはbourneシェルとksh、およびbashに存在することに注意してください。
ghoti 2012

参照してください:tldp.org/LDP/abs/html/special-chars.html
choroba

6
これは本当の質問ではないのですか?本当にいい質問だと思います。私もそれをうまく利用していますが、答えを投稿することはできません。
Steven Lu

回答:


175

歴史的な理由からもっとあります。ビルトインコロン:は、とまったく同じtrueです。true戻り値が重要な場合、たとえば無限ループで使用するのが伝統的です。

while true; do
  echo 'Going on forever'
done

:シェルの構文にコマンドが必要な場合に使用するのが伝統的ですが、何もする必要はありません。

while keep_waiting; do
  : # busy-wait
done

:組み込みの日付に戻ってすべての方法トンプソンシェル、それはだった現在ではUnixのV6:Thompsonシェルのgoto声明のラベルインジケーターでした。ラベルは任意のテキストにすることができるので:、コメントインジケータとして二重に使用されます(がない場合goto comment: comment事実上コメントです)。Bourneシェルではありませんでしたgotoが、保管します:

一般的なイディオムの用途があること:: ${var=VALUE}、どのセットvarVALUEそれが未設定だった場合は何もしない場合はvar、既に設定されました。この構造は変数置換の形でのみ存在し、この変数置換は何らかの形でコマンドの一部である必要があります。no-opコマンドはうまく機能します。

参照してくださいコロンの組み込みが機能しない何の目的?


11
良い要約。また、元のBourneシェルは#コメント(または#!/bin/shシバン)に使用していませんでした。::このコマンドは、コメントを導入し、そして悲哀彼らのコメントに星の素敵な箱を作ったナイーブプログラマbetide : ****(または、より悪いです: * * *)。
ジョナサンレフラー

3
@JonathanLeffler:私には恥ずかしいけど、私には理解できません。どうなるの: * * *
DevSolar 2014年

7
:はコマンドであるため、シェルは引数を:無視する前に引数を処理する必要があります。ほとんどの場合、*現在のディレクトリにあるファイルのリストに展開する際に、シェルに追加の作業を行わせるだけです。スクリプトの動作には実際には影響しません。
chepner 2014年

多くのファイルがあるディレクトリで実行すると、グロブの展開がコマンドの長さの制限を超えると、スクリプトが失敗する可能性があります。多分あなたが持っている場合のみset -e。とにかく、うまくいけば私たちはすべて使用に同意することができます#:)
Jack O'Connor

2
while : ; do ... ; done速くて汚い無限ループが必要な場合に使用します。(通常sleep、ループにa があり、Ctrl-Cを入力して強制終了します。)
キース・トンプソン、

21

すべてのコードをコメントアウトするときに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'

バッシュは空のブロック(WTF)を持つことはできません。だからあなたは何もしないを追加します:

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

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

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

12

を使用するset- e場合|| :は、障害が発生した場合にスクリプトを終了しないようにするための優れた方法です(明示的に成功させます)。


1
これは、特定のシェルスクリプト呼び出しアプリケーションに役立つことがわかりました。たとえば、MacのAutomatorはエラーで終了し、理由を教えません。ただし|| :、後で使用してエラーを自分で処理すると、exit 0デバッグ中にすべてのstdoutとstderrをアプリウィンドウに表示できます。{ foo ... 2>&1; } || :より複雑なトラップとif-thenを設定するよりもはるかに簡単な方法を検討してください。
Beejor

7

:成功するが何もしないコマンドを提供するために使用します。この例では、「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  

厳密に言うと、変数に値を割り当てることは「何かをすること」であり、それがなぜcase文でエラーをスローしないのかということです。
qodeninja 2017

@qodeninja:変数の割り当てが「何もしなかった」と主張した人はいません。重要なのは、後者は$(verbosity $i)(そして条件付きで)何もしないことです。
軌道の軽さの競争

6

alias引数を無視する

引数を取らないエイリアスが必要な場合があります。あなたはそれを使ってそれを行うことができます:

> alias alert_with_args='echo hello there'

> alias alert='echo hello there;:'

> alert_with_args blabla
hello there blabla

> alert blabla
hello there

反対投票者ではありませんが:、残念ながらこの答えはどのように機能するかを示していません。あなたが提供した例は冗長なようです。
qodeninja 2017

2
問題は、それがどのように機能するかではなく、ユースケース何であるかです。私の答えはstackoverflow.com/a/37170755/6320039と少し似ています。しかし、それは実際には同じユースケースではありません。私は私の答えを改善してよかったのですが、私は本当にここでどのように知っているのではありません...
Ulysse BN

1
これは少しファンキーです-コーナーケースですが、もし面白いかもしれませんが、それでも興味深いのは、バックポケットに入れるのが賢明なトリックになる可能性があることです。
マイクS

2
同じことがで達成することができる#
ゾーイHewll

2
@ZoeyHewll、かなりではありません。エイリアスは、あらゆる種類の実行の前にテキストで置換さ#れるため、エイリアスを使用すると、同じ行に構文的に続くすべてが無視されます。これは(考える本当に異なっているmy_alias arg ; other_command、逆に、または my_alias arg1 {BACKSLASH}{NEWLINE} arg2)、あなたはそれが構文エラーを(何を推測する原因となり望むものはおそらくないですwhile my_alias ; do true ; donewhile true ; do my_alias ; done行います)。
Maëlan

4

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

: << 'EOF'

This part of the script is a commented out

EOF

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


クールなトリック!特に、ハードラップしたときに数十の「#」を必要とするスクラッチノートやコードの場合。副作用として、コメント行とは異なり、一部の構文ハイライターはヒアドキュメントを無視し、通常のコード(または少なくともプレーンテキスト)のように色付けします。これは、コメントアウトされたコードを調べたり、段落から目をネオンのコメント色で保存したりするのに最適です。唯一の注意点は、構文は一意であり、混乱を引き起こす可能性があるため、そのようなブロックは共有コード内のコメントであることを示す必要があることです。繰り返しになりますが、これは私たちが話しているシェルであり、混乱の可能性は体系的です。
Beejor

3

私の二つ。

PODコメントを埋め込む

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

ランタイム関数バインディング

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

#!/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

2

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

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

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

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

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回。頻繁に発生するので、注意する必要があります。(言語に関係なく)コードの可読性が向上すると思うときは、私はそれを使うことをためらいません。


3
の目的について質問に回答する場合は、回答ではなく、:を使用してください。つまり、ここで条件を否定する最も簡単な方法は、1つのコマンドを使用し、その前に:を付けることです。:true[[ ... ]]!if ! [[ ( ... && ... ) || ( ... && ... ) ]]; then
chepner 2014年

1
ああ、とてもいいです、そして私は私の答えに反対票を投じるべきです。うーん....私はまだ何もしない句を使用しなければならなかった例を考えています。これは私が思いついた最高のものです。
Bitdiot 2014年

それは後方互換性のために実際に保持されているだけ: ${...=...}ですが、間違いなくほど不自然ではありませんtrue ${...=...}。一部が好むかもしれないwhile :; dowhile true; doだけでなく、簡潔さのために。
chepner 2014年

2

この回答に多少関係しているのですが、この何もしないのは、ポリグロットスクリプトをハックするのにかなり便利です。たとえば、bashとvimscriptの両方に有効なコメントは次のとおりです。

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

確かに、私たちもtrue同様に使用した可能性があります:が、句読記号であり、無関係な英語の単語ではないため、それが構文トークンであることは明らかです。


なぜ誰かが(それはクールであることに加え)ポリグロットスクリプトを書くようなトリッキーなことをするだろう:それは我々が正常にファイルがで、いくつかの異なる言語で複数のスクリプトファイルを記述します状況で役立つ証明しXたファイルを参照しますY

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

  • 一般的な例。シバンには、よく知られている長期にわたる問題があります。ほとんどのシステム(LinuxおよびCygwinを含む)では、インタープリターに渡すことができる引数は1つだけです。次のシバン:

    #!/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"。これはオプションで実行できます。ただし、その設定はかなりのものだったので、文字列にインライン化するのはひどいものでした(可能な場合)。したがって、より良い解決策は、extensoの設定ファイルにそれを書き込んでから Vimにそのファイルをで読み込ませることです-S "/path/to/file"。したがって、私はpolyglot bash / vimscriptファイルを作成しました。


1

スクリプトでデフォルト変数を定義するためにも使用しました。


: ${VARIABLE1:=my_default_value}
: ${VARIABLE2:=other_default_value}
call-my-script ${VARIABLE1} ${VARIABLE2}

0

別の成功につなげたいコマンドがあるとします。

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

しかし、ここで条件付きでコマンドを実行し、実行されるコマンド(ドライラン)を表示したいとします。

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 || :
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.