我有许多字符串参数传递给 bash 函数,每个参数都打印在单独的行上。
想要修改代码,使得 的数值warn
是从 中的第一个参数开始以红色打印的行数${@}
。
rge='^[0-9]+$'
if [[ -v warn && "$warn" == "1" ]]; then
printf '%s\n' ${red}"$1"${sgr} # first line red
printf '%s\n' "${@:2}" # remaining, uncoloured
elif [[ -v warn && "$warn" =~ $rge ]]; then
printf '%s\n' ${red}"$@"${sgr} # all lines red
fi
作为第一次尝试,我有
elif [[ -v warn && "$warn" =~ $rge ]]; then
argc=$#
argv=("$@")
printf "%s\n" "argc: $argc"
for (( j=0; j<warn; j++ )); do
printf '%s\n' ${red}"${argv[j]}"${sgr}
done
#printf '%s\n' ${red}"$@"${sgr} # all lines red
fi
答案1
利用现有工具,这些工具已经知道如何根据各种条件(包括输入行号)执行不同的操作。例如 awk、sed、perl、python 等。
顺便说一句,你可以在 sh 中执行此操作,但为什么要这么做呢?对于任何形式的文本处理来说,shell 循环几乎总是最糟糕的方式。
例如,下面使用 shell 设置环境变量,然后awk
进行颜色突出显示(以避免 a)计算 shell 中的行数和 b)使用 shell while read 循环缓慢而笨拙地执行一些快速而简单的操作awk
)
colourise() {
# colourise all (default) or the first N lines of stdin
# where N is the optional first argument to the function.
# check if arg is empty or numeric
[ -z "$1" ] || [[ "$1" =~ ^[0-9]+$ ]] \
|| echo "optional arg must be numeric if supplied" && exit 1
local colour="$(tput setaf 9)"
local sgr0="$(tput sgr0)"
awk -v c="$colour" -v s="$sgr0" -v w="$1" \
'(NR <= w || w == "") {print c $0 s; next}1'
}
顺便说一句,您可以直接在 awk 脚本中硬编码颜色代码和 sgr 代码...然后您只需将“$1”值传递给 awk (或者,export warn="$1"
在 shell 中并在 awk 中使用 ENVIRON["warn"] ) 。但请注意,awk 没有函数tput
,因此您必须手动执行此操作。例如,以下内容适用于大多数类似于 vt100 或 ansi 或 xterm 的终端。
colourise() {
local warn="$1"
export warn
awk 'BEGIN {c="\033[91m"; s="\033[m\017"; w=ENVIRON["warn"]}
(NR <= w || w == "") {print c $0 s; next}1'
}
或者(因为对终端进行硬编码转义序列并不好):
colourise() {
local warn="$1"
local colour="$(tput setaf 9)"
local sgr0="$(tput sgr0)"
export warn colour sgr0
awk 'BEGIN {c=ENVIRON["colour"]; s=ENVIRON["sgr0"]; w=ENVIRON["warn"]}
(NR <= w || w == "") {print c $0 s; next}1'
}
然后将您喜欢的任何内容通过管道传递到colourise
函数中。例如
# colourise first three lines of an array
printf "%s\n" "${array[@]}" | colourise 3
# colourise all lines of head
head filename | colourise
# colourise only the first line of the output from several
# commands. use a compound command {} or a sub-shell ()
# this does not colourise the first line of each command separately,
# only the first line of the combined output.
{
command1
command2
command3
} | colourise 1
答案2
已解决问题如下
if [[ -v f ]] && (( f != 0 )); then
# print normal multi-line text
[[ ! -v warn ]] && printf '%s\n' "$@"
# print multi-line warnings
if [[ -v warn && "$warn" =~ $rge ]]; then
argc=$#
argv=("$@")
rge='^[0-9]+$'
(( warn > argc )) && warn=$argc
for (( j=0; j<argc; j++ )); do
(( j+1 <= warn )) && printf '%s\n' ${red}"${argv[j]}"${sgr}
(( j+1 > warn )) && printf '%s\n' "${argv[j]}"
done
#printf '%s\n' ${red}"$@"${sgr} # all lines red
fi
fi