基于数值的着色参数

基于数值的着色参数

我有许多字符串参数传递给 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

相关内容