私がbashスクリプトを書くとき、私は通常この方法で冗長モードを取得します(簡略化):
_V=0
while getopts "v" OPTION
do
case $OPTION in
v) _V=1
;;
esac
done
そして、「詳細な出力」が必要なときはいつでも、次のように入力します。
[ $_V -eq 1 ] && echo "verbose mode on" || echo "verbose mode off"
または例えばこれ:
[ $_V -eq 1 ] && command -v || command
よりエレガントにする方法はありますか? 「verbose」という名前の関数を定義して[ $_V -eq 1 ]
の代わりに入力することを考えていましたが、これは小さな改善にすぎません。
きっともっと一般的な方法があります…
お気づきのとおり、log
、log_debug
、log_error
などのlog
関数を定義できます。
function log () {
if [[ $_V -eq 1 ]]; then
echo "$@"
fi
}
メインコードの読みやすさを向上させ、show\nonshowロジックをログ機能に隠すことができます。
log "some text"
_V
(グローバル変数)が等しい場合1
「一部のテキスト」が印刷されますが、それ以外の場合は印刷されません。
他のすべての投稿を読んだ後、私はこれを思いつきました
# set verbose level to info
__VERBOSE=6
declare -A LOG_LEVELS
# https://en.wikipedia.org/wiki/Syslog#Severity_level
LOG_LEVELS=([0]="emerg" [1]="alert" [2]="crit" [3]="err" [4]="warning" [5]="notice" [6]="info" [7]="debug")
function .log () {
local LEVEL=${1}
shift
if [ ${__VERBOSE} -ge ${LEVEL} ]; then
echo "[${LOG_LEVELS[$LEVEL]}]" "$@"
fi
}
次に、このように簡単に使用できます
# verbose error
.log 3 "Something is wrong here"
どちらが出力されます
[error] Something is wrong here
#!/bin/bash
# A flexible verbosity redirection function
# John C. Petrucci (http://johncpetrucci.com)
# 2013-10-19
# Allows your script to accept varying levels of verbosity flags and give appropriate feedback via file descriptors.
# Example usage: ./this [-v[v[v]]]
verbosity=2 #Start counting at 2 so that any increase to this will result in a minimum of file descriptor 3. You should leave this alone.
maxverbosity=5 #The highest verbosity we use / allow to be displayed. Feel free to adjust.
while getopts ":v" opt; do
case $opt in
v) (( verbosity=verbosity+1 ))
;;
esac
done
printf "%s %d\n" "Verbosity level set to:" "$verbosity"
for v in $(seq 3 $verbosity) #Start counting from 3 since 1 and 2 are standards (stdout/stderr).
do
(( "$v" <= "$maxverbosity" )) && echo This would display $v
(( "$v" <= "$maxverbosity" )) && eval exec "$v>&2" #Don't change anything higher than the maximum verbosity allowed.
done
for v in $(seq $(( verbosity+1 )) $maxverbosity ) #From the verbosity level one higher than requested, through the maximum;
do
(( "$v" > "2" )) && echo This would not display $v
(( "$v" > "2" )) && eval exec "$v>/dev/null" #Redirect these to bitbucket, provided that they don't match stdout and stderr.
done
# Some confirmations:
printf "%s\n" "This message is seen at verbosity level 3 and above." >&3
printf "%s\n" "This message is seen at verbosity level 4 and above." >&4
printf "%s\n" "This message is seen at verbosity level 5 and above." >&5
冗長レベル(Bash 4)を備えたより柔軟なシステムでの最初の試み:
# CONFIG SECTION
# verbosity level definitions
config[verb_levels]='debug info status warning error critical fatal'
# verbosity levels that are to be user-selectable (0-this value)
config[verb_override]=3
# user-selected verbosity levels (0=none, 1=warnings, 2=warnings+info, 3=warning+info+debug)
config[verbosity]=2
# FUNCTION DEFINITIONS SECTION
_messages() {
# shortcut functions for messages
# non overridable levels exit with errlevel
# safe eval, it only uses two (namespaced) values, and a few builtins
local verbosity macro level=0
for verbosity in ${config[verb_levels]}; do
IFS="" read -rd'' macro <<MACRO
_$verbosity() {
$( (( $level <= ${config[verb_override]} )) && echo "(( \${config[verbosity]} + $level > ${config[verb_override]} )) &&" ) echo "${verbosity}: \$@";
$( (( $level > ${config[verb_override]} )) && echo "exit $(( level - ${config[verb_override]} ));" )
}
MACRO
eval "$macro"
(( level++ ))
done
}
# INITIALIZATION SECTION
_messages
初期化後、コード内のどこでも次のようなものを使用できます。
! (( $# )) && _error "parameter expected"
[[ -f somefile ]] && _warning "file $somefile already exists"
_info "some info"
_status "running command"
if (( ${config[verbosity]} <= 1 )); then
command
else
command -v
fi
# explicitly changing verbosity at run time
old_verbosity=${config[verbosity]}
config[verbosity]=1
等.
私はまた、簡単なifelseを行うためにこの関数を思いつきました:
function verbose () {
[[ $_V -eq 1 ]] && return 0 || return 1
}
これは、$ _ Vが1に設定されている場合にコマンドを実行します。次のように使用します。
verbose && command #command will be executed if $_V == 1
または
verbose && command -v || command # execute 'command -v' if $_V==1, else execute 'command'
何かをログに記録するたびに「if」ステートメントを実行したくない場合は、このアプローチを試すことができます(これが私が行う方法です)。
log
を呼び出す代わりに、代わりに$echoLog
を呼び出すという考え方です。したがって、冗長モードの場合、$echoLog
はecho
になりますが、非冗長モードの場合、何も出力せず、引数を無視する関数です。
コピーできるコードは次のとおりです。
# Use `$echoLog` everywhere you print verbose logging messages to console
# By default, it is disabled and will be enabled with the `-v` or `--verbose` flags
declare echoLog='silentEcho'
function silentEcho() {
:
}
# Somewhere else in your script's setup, do something like this
while [[ $# > 0 ]]; do
case "$1" in
-v|--verbose) echoLog='echo'; ;;
esac
shift;
done
これで、$echoLog "Doing something verbose log worthy"
のような行をどこにでもドロップできます。
verbose=false
while getopts "v" OPTION
do
case $OPTION in
v) verbose=true
;;
esac
done
その後
$verbose && echo "Verbose mode on" || echo "Verbose mode off"
これは/bin/true
または/bin/false
を実行し、それぞれ0または1を返します。
複数のifステートメントの使用や関数名を保持するための変数の使用を回避するには、冗長性に基づいてさまざまな関数を宣言してみてください。
これは、bashだけでなく、すべてのボーンシェルデリバティブで機能します。
#verbose=verbose_true # uncomment to make script verbose
if [ "$verbose" ]; then
log() { echo "$@"; }
else
log() { :; }
fi
log This Script is Verbose
注: "verbose = verbose_true"を使用すると、スクリプトのトレースが大幅に改善されますが、必要に応じてスクリプトをトレースできます。