91
69

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

シェルスクリプト(Bash): \ で改行してる時の 1 行コメントアウト

Last updated at Posted at 2015-04-13

シェルのコマンドで、オプションがたくさんあるときは、読みやすくするために改行することがあると思う。

somecommand --optionA=xxxx \
            --optionB=yyyy \
            --optionC=zzzz \
            --optionD=wwww

しかし、これを部分的にコメントアウトする時(たとえばオプションの組み合わせを試す際)

somecommand --optionA=xxxx \
            --optionB=yyyy \
            # --optionC=zzzz \
            --optionD=wwww

のようにコメントアウトして失敗した経験は、皆さんにはないだろうか?

echo での例示

たとえば、↓のようなシェルスクリプトを

sample.sh
#!/usr/bin/env bash

echo 'a' 'x' \
     'b' 'y' \
     'c' 'z' \
     'd' 'w'

コメントアウトして

sample.sh(コメントアウト後)
#!/usr/bin/env bash

echo 'a' 'x' \
     'b' 'y' \
     # 'c' 'z' \
     'd' 'w'

のようにして実行すると、

実行結果
$ ./sample.sh
a x b y
./sample.sh: line 6: d: command not found
$

と、このように。
コメントアウト以降が独立したステートメントとして扱われるため d を実行しようとする。
この例では d というコマンドがなかったから良いものの、
存在するようなケースでは致命傷を生む可能性がある。

回避策を考えてみた

よくある /* */ な範囲コメントアウトができれば、このような悲劇は避けられると思った。
1 行の範囲コメントを発明したい。

ヒアドキュメントを使う方法

シェルの範囲コメントアウトといえば、ヒアドキュメントとヌルコマンドを利用した方法が一般的だ。
クオートで囲めば、変数やコマンド置換の評価も止められる。

:<<'EOT'
somecommand
foo
bar
buzz
EOT

でもコレは複数行が前提に成ってしまうのでダメだ。
これをオプションの中でやりたい。

外側を式で囲む

行を $(:)\ で囲む戦法を思いついたのでやってみた。
コマンド置換でヌルコマンドに対して引数が渡るので、置換後は空になるというわけだ。
コマンド置換はダブルクォートで囲まないので、空文字列が挿入されることもない。

sample.sh(改)
#!/usr/bin/env bash

echo 'a' 'x' \
     'b' 'y' \
     $(: 'c' 'z' \ )\
     'd' 'w' 
実行結果
$ ./sample.sh
a x b y d w
$

これは一見よさそうだ。
このパターンだけならこれで正解。

さらなる問題

しかし ↑ ではコメントアウト対象が単なる文字列だったので済んだが、元のスクリプトが次のような例だとダメだ。

sample2.sh
#!/usr/bin/env bash

function inc () {
    echo 'called!' "$*" > /dev/tty
}

echo 'a' "$(inc 'x')" \
     'b' "$(inc 'y')" \
     'c' "$(inc 'z')" \
     'd' "$(inc 'w')" 

これを上記の方法で c の行をコメントアウトして実行してみよう。

sample2.sh(改)
#!/usr/bin/env bash

function inc () {
    echo 'called!' "$*" > /dev/tty
}

echo 'a' "$(inc 'x')" \
     'b' "$(inc 'y')" \
     $(: 'c' "$(inc 'z')" \ )\
     'd' "$(inc 'w')" 
実行結果
$ ./sample2.sh
called! x
called! y
called! z
called! w
a  b  d
$

ご覧のとおり、 c の行の $(inc 'z') は評価されてしまっている。
こいつもトラップだ。

短絡評価する

最終的に思いついたのがコレ
$(:||:)\ で囲む方法

sample2.sh(改2)
#!/usr/bin/env bash

function inc () {
    echo 'called!' "$*" > /dev/tty
}

echo 'a' "$(inc 'x')" \
     'b' "$(inc 'y')" \
     $(:||: 'c' "$(inc 'z')" \ )\
     'd' "$(inc 'w')" 
実行結果
$ ./sample2.sh
called! x
called! y
called! w
a  b  d
$

これで平和になった…。

まとめ

これが今思いついている中では、最も万能な 1 行コメントアウトの方法だと思う。(たぶん)
それにしても、あまりに技巧的なやり方過ぎてしっくりこない……。

そしておそらく、この解決法にもさらなる落とし穴があるに違いない。(落とし穴募集)

ところで

$(:||: )\

ちょっとかわいい顔文字みたいだと思いません?

91
69
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
91
69

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?