POSIX error
シェルコードにsh
関数があります。それは本質的に次のように見えます
error () {
printf 'utility: ERROR: ' >&2
printf "$@" >&2
}
2番目のprintf
は、たとえばを使用して関数を呼び出すことができるようにします。
error 'Something relating to "%s" went wrong!\n' "$thing"
exit 1
この関数は、メッセージの前に文字列utility: ERROR:
を付け、printf
の場合と同じように書式設定文字列を使用できる間、すべてが標準エラーに送信されるように調整します。
明らかに、 ShellCheck 2番目のprintf
について文句を言い、
SC2059:printfフォーマット文字列で変数を使用しないでください。 printf "..%s .." "$ foo"を使用します
私がやっていることを実行して、この警告を無視するのは「安全」ですか(コードに# shellcheck disable=SC2059
コメントを付けて無効化することもできます) ?注:私は常にerror
関数を正確に使用するのと同じように、つまり静的な一重引用符でprintf
を使用します。最初の引数。
「安全ですか?」ここで、「私の関数は、適切な方法でprintf
の周りの(リダイレクトを除いて)同様のラッパーとして機能しますか?」という意味です。
ここでは、フォーマットが引数として渡されることを意図しているので安全です。ただし、関数を使用するときは、それがフォーマットであることを覚えておく必要があります。したがって、リマインダーとして関数にerrorf
という名前を付ける必要があるかもしれません。
次のように使用した場合:
_error "invalid arg: $arg"
_
_$arg
_のような_%99999999s
_の値のような問題が発生します
理想的には、最初の引数に変数が含まれているprintf
の使用法にフラグを立てるために、printf
andの使用法を無視するようにshellcheckに指示する必要があります。
いくつかの注意事項:
printf
を2回呼び出しているので、少なくとも2回のwrite()
システムコールになります。違いが生じる可能性はほとんどありません。また、printf
のような一部のbash
実装は、状況によってはいくつかのシステムコールを実行することに注意してください。 problem私が考えているのは、エラーメッセージの2つの部分が、並行して実行されている別のコマンドの出力と絡み合っていることです。_error "%s\n" error1 error2
_では、プレフィックスは最初のエラーに対してのみ出力されます。それがあなたがそれをしたい方法であるならば、それは大丈夫です。次のこともできます。
_errorf() { printf "utility: ERROR: $@" >&2; }
_
プレフィックスがフォーマットの前に付加されるため、フォーマットが再利用されるたびに出力されます(これにより、複数のwrite()
issueにも対応します)。
ただし、utility
を変数にしたい場合は、これは機能しません。
_PROG_NAME = $ {0 ## * /} errorf(){printf>&2 "$ PROG_NAME:ERROR:$ @"; }
$0
_に_%
_または_\
_が含まれていると失敗するため、問題ありません。そして
フォーマットが再利用される場合は機能しません(つまり、ユーザーは_PROG_NAME = $ {0 ## * /} errorf(){ format = $ 1; shift printf>&2 "%s:ERROR:$ format" "$ PROG_NAME" "$ @" }
%<n>$d
_ディレクティブを1つオフセットする必要があります(移植性がないため、これらを使用することをお勧めしません)。 )。_\
_と_%
_を_$PROG_NAME
_で手動でエスケープする以外に、簡単な回避策は考えられません。それでも、多くのprintf
実装のように簡単ではありません。 、_0x5c
_以外の文字にある_\
_バイトもエスケープする必要があります(BIG5やGB18030などのいくつかの文字セットの場合)。