printf를 사용하여 텍스트를 중앙에 배치

printf를 사용하여 텍스트를 중앙에 배치
printf "%*s\n" $(((${#fname}+$COLUMNS)/2)) "$fname"

다음 오류가 발생합니다.

line 9: (7+)/2: syntax error: operand expected (error token is ")/2")

이것은 터미널에서는 작동하지만 내 스크립트에서는 작동하지 않습니다. 어떤 생각이 있나요?

답변1

모든 쉘이 $COLUMNS변수를 터미널 너비로 설정하는 것은 아닙니다.

bash5.0 이전 버전에서는 스크립트가 아닌 대화형으로만 설정됩니다. 그러나 버전 4.3부터는 비대화형 셸에서 계속 사용할 수 있습니다 shopt -s checkwinsize.

그러나 두 경우 모두 반전이 있습니다. 비대화형 셸에서 옵션을 활성화하면(5.0부터 기본적으로 활성화됨) $COLUMNS하위 프로세스가 기다리고 종료될 때까지 /가 설정되지 않습니다(소스에 언급된 항목).$LINESNEWS포그라운드 작업이 종료된 후, 비대화형 쉘에는 기본적으로 작업 제어가 없기 때문에 약간 오해의 소지가 있습니다. 따라서 이러한 변수를 사용하기 전에 외부 명령이나 하위 셸이 동기적으로 실행되는지 확인해야 합니다.

#! /bin/bash -
shopt -s checkwinsize # for versions 4.3 and 4.4
(:) # start a synchronous subshell that runs the null command
echo "$COLUMNS $LINE"

또한 이는 stderr이 터미널로 이동할 때만 발생하므로(그렇지 않은 경우 설정되지 않은 상태로 유지됨) 화면 너비를 결정할 수 없는 경우 $COLUMNS보다 합리적인 기본값을 사용하는 것이 좋습니다 .${COLUMNS:-80}bash

또는 터미널에서 실행 중인 경우 비대화형인 경우에도 zsh항상 설정하도록 전환하거나( 그렇지 않으면 기본값은 80) Bourne과 유사한 셸에서 if 출력을 사용하여 이전에 설정 한 경우 설정할 수 있습니다. 설정되지 않았거나 비어 있습니다.$COLUMNS$COLUMNS${COLUMNS:=$(tput cols)}$COLUMNS$COLUMNStput cols

tput cols시스템에서 작동하지 않으면 시도해 볼 수 있습니다 . </dev/tty stty size | awk '{print $2}'또는zsh -c 'print $COLUMNS'

그러나 이 방법으로 설정하면 터미널 크기가 조정될 때마다 업데이트되지 않으므로 스크립트에서 가운데 ​​정렬된 텍스트를 인쇄할 때마다 터미널 크기가 쿼리되도록 항상 대신 $COLUMNS사용하는 것이 좋습니다 .$(tput cols)

또한 참고하세요printf '%*s'zsh쉘 외부에서 fish주어진 양만큼 텍스트를 채우고바이트아니요수치따라서 이 방법은 UTF-8을 사용하는 로케일에서 US-ASCII 문자(가능한 모든 문자의 0.011%)로 제한되는 단일 바이트, 단일 너비 문자가 포함된 텍스트를 채우는 데에만 사용할 수 있습니다.

zsh대신 을 사용하는 경우 대신 eft 및 ight 패딩 매개변수 bash와 함께 확장 플래그를 사용할 수 있습니다 (이 플래그를 사용하여 너비가 0이거나 너비가 2개인 문자를 처리할 수도 있습니다 ).lrm

print -r -- ${(ml[COLUMNS/2]r[COLUMNS-COLUMNS/2])fname}

왼쪽과 오른쪽(즉, 화면의 오른쪽 가장자리)을 채우는 점에 유의하세요. 다음을 사용하여 오른쪽 패딩(및 후행 공백)을 제거할 수 있습니다.

set -o extendedglob
print -r -- ${${(ml[COLUMNS/2]r[COLUMNS-COLUMNS/2])fname}%%[[:space:]]#}

색상 지정/굵게/강조 표시... 이스케이프 시퀀스가 ​​포함된 중앙 텍스트는 더 복잡합니다. 가장 쉬운 방법은 아마도 문자열 너비를 얻기 전에 제거하는 것입니다. 예를 zsh들어그 방법문자열 너비를 결정하고 너비가 0이거나 너비가 2개인 문자를 처리합니다.

varwidth() (( ${(P)#1} * 3 - ${#${(ml[${(P)#1} * 2])${(P)1}}} ))
functions -Ms varwidth

varwidth_without_formatting() {
  set -o localoptions -o extendedglob
  local without_formatting=${(P)1//$'\e'\[[0-9;]#m}
  (( varwidth(without_formatting) ))
}
functions -Ms varwidth_without_formatting

center() {
  local text
  for text do
    print -r -- ${(l[(COLUMNS-varwidth_without_formatting(text))/2])}$text
  done
}

center $'\e[31mred\e[1;39mbold\e[m' \
       ${(%):-%F{green}Blah%F{yellow}blah%F{magenta}blah%f}

1 대부분의 시스템에서는 @zevzek이 주석에 표시한 것처럼 SIGWINCH 신호에 대한 처리기를 설치할 수 있지만 이는 가장 일반적인 경우에 도움이 될 것입니다.

답변2

COLUMNS 변수 대신 외부 소스에서 값을 가져올 수 있습니다.

tput cols 

stty size | cut '-d ' -f1

답변3

다음을 시도해 보십시오:

read WindowHeight WindowWidth<<<$(stty size)
printf "%$(((${#fname}+${WindowWidth})/2))s" "$fname"

COLUMNS는 스크립트에서 자동으로 설정되지 않으므로 가장 좋은 옵션은 stty를 사용하여 현재 창 크기를 얻는 것입니다. 이는 여러 쉘(bash, ksh, zsh 포함)에서 작동합니다.

관련 정보