숫자 기반 셰이딩 매개변수

숫자 기반 셰이딩 매개변수

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에서도 할 수 있는데 왜 그럴까요? 쉘 루프는 거의 항상 모든 형태의 텍스트 처리를 수행하는 최악의 방법입니다.

예를 들어, 아래에서는 셸을 사용하여 환경 변수를 설정한 다음 awk색상 강조 표시를 수행합니다(a) 셸의 줄 수 계산 및 b) 읽기 루프 동안 셸을 사용하여 빠르고 어색하게 빠르고 간단한 작업을 수행하는 것을 방지합니다 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"쉘에서 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

관련 정보