2011-12-10 34 views
16

當我寫的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 ],但這只是一個小小的改進。

我敢肯定,有做更常見的方式...

回答

25

當你發現,你可以定義一些log功能,如loglog_debuglog_error

function log() { 
    if [[ $_V -eq 1 ]]; then 
     echo "[email protected]" 
    fi 
} 

它可以有助於提高主代碼的可讀性,並將show \ nonshow邏輯隱藏到日誌功能中。

log "some text"

_V如果(全局變量)等於1「一些文本」將被打印,在其他情況下,它不會。

2

我也想出了這個功能做一個快速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' 
1
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。

+0

'''true'''或'''false'''將不會被執行,你只是處理字符串。 – phk

2

第一次嘗試在具有詳細級別更靈活的系統(擊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}: \[email protected]"; 
      $((($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 

+0

哇!這是否對Bash 3有效? (我僅限於Bash 3.2) – tamasgal

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

如果你想避免做一個「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"這樣的行。

13

閱讀所有其他職位後,我想出了這個

# 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]}]" "[email protected]" 
    fi 
} 

然後,你可以簡單地使用它像這樣

# verbose error 
.log 3 "Something is wrong here" 

將輸出

[error] Something is wrong here 
+0

這比其他答案的開/關方式好得多。 字符串和值之間的映射作爲矢量是一個很好的附加組件,並使它類似於python中的實現。 –

0

以避免使用多個如果聲明或使用一個變量來保存一個函數名稱如何聲明基於ve的不同函數rbosity!

這適用於所有bourne shell衍生物而不僅僅是bash!

#verbose=verbose_true  # uncomment to make script verbose 
if [ "$verbose" ]; then 
    log() { echo "[email protected]"; } 
else 
    log() { :; } 
fi 

log This Script is Verbose 

注意:使用「詳細= verbose_true」使得腳本跟蹤要好很多 ,但你可以做一個,如果你喜歡的。

0

我建議@fentas的回答修改後的版本:

# 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 
    if [ -t 0 ]; then 
     # seems we are in an interactive shell 
     echo "[${LOG_LEVELS[$LEVEL]}]" "[email protected]" >&2 
    else 
     # seems we are in a cron job 
     logger -p "${LOG_LEVELS[$LEVEL]}" -t "$0[$$]" -- "$*" 
    fi 
    fi 
}