형식화된 출력: 밑줄

형식화된 출력: 밑줄

ksh첫 번째 인수를 화면에 인쇄하고 -적절한 수의 문자에 밑줄을 긋는 다음 함수를 작성했습니다 .

print_underlined () {
    word=$1 
    echo $word

    i=${#word}
    while [[ i -gt 0 ]]; do
        printf "-"
        (( i = $i - 1 ))
    done
    printf "\n"
}

예:

$ print_underlined foobar
foobar
------
$

밑줄 친 단어를 화면에 표시하는 더 간단하고 우아한 방법이 있는지 궁금합니다.

기록을 위해 다음을 사용하고 있습니다.

  • 솔라리스 10
  • 크쉬 88

답변1

문제의 핵심은 기존 문자열과 길이가 동일한 밑줄로만 구성된 문자열을 구성하는 것입니다. 최신 버전 의 bash, ksh 또는 zsh에서는 다음 구문을 사용하여 이 문자열을 작성할 수 있습니다 ${VARIABLE//PATTERN/REPLACEMENT}. underlines=${word//?/_}그러나 이 구성은 ksh88에는 존재하지 않습니다.

모든 쉘에서 사용할 수 있습니다 tr. POSIX 호환 구현을 사용하면 tr다음을 작성할 수 있습니다.

underlines=$(printf %s "$word" | tr -c '_' '[_*]')

저는 Solaris 10이 기본적으로 POSIX와 호환된다고 생각 tr하지만, 레거시 구현이 있을 수도 있습니다(이전 Solaris 버전과 호환 가능). 의 역사적 구현은 구문을 tr이해하지 못할 수도 있지만 [x*]다음 구문(POSIX에서는 보장되지 않음)을 허용하는 경향이 있습니다. 이는 "개행 문자가 아닌 모든 항목을 "로 바꾸십시오 _"를 의미합니다.

underlines=$(echo "$word" | tr -c '\010' '_')
underlines=${underlines%_}

다음은 루프나 외부 프로그램을 사용하지 않고 Bourne 쉘에서 작동하는 약간 미친 방법입니다(적어도 도입 이후 set -f- 빈 디렉토리에서 실행하면 부족함이 완화되지만 set -f). 안타깝게도 문자열에 공백이 포함되어 있지 않은 경우에만 작동합니다.

set -f          # turn off globbing
IFS=$word       # split at any character in $word
set a $word     # split $word into one word between each character, i.e. empty words
shift           # remove the leading a (needed in case $word starts with -)
IFS=_
underlines=$*   # join the empty words, separated with the new value of $IFS

더 복잡한 변형은 공백을 처리하지만 연속된 공백 시퀀스가 ​​없는 경우에만 해당됩니다. 공백 문자 시퀀스는 IFS항상 축소되므로 이 트릭을 더 이상 사용할 수 없을 것 같습니다 .

set -f
unset IFS; set a $0    # split at whitespace
IFS=$*; set $*         # split into empty words
IFS=_; underlines=$*   # collect the empty

답변2

최신 쉘에서는 다음을 수행할 수 있습니다 printf %s\\n "${word//?/-}". 나는 ksh88에 특별한 확장자가 없다고 생각합니다.

추가 프로세스가 마음에 들지 않으면 이렇게 할 수 있습니다 printf %s\\n "${word}" | sed -e 's/./-/g'.

귀하의 접근 방식도 훌륭하지만 다음과 같이 약간 변경하겠습니다.

print_underlined () {
        word=$1
        printf %s\\n "$word"
        i=${#word}
        while (( i )); do
                printf -
                (( i = i - 1 ))
        done
        echo
}

완전히 다른 접근 방식을 사용하려면 터미널의 기능을 사용하여 실제 밑줄을 표시하십시오(사용 가능한 경우).

tput smul; printf %s\\n "$word"; tput rmul

물론 이는 스크립트가 실행 중인 터미널이 이를 지원하는지 아는 경우에만 작동합니다.

답변3

나는 단지 인터넷 검색으로 이것을 찾았습니다.

underline() { echo $1; echo "${1//?/${2:--}}";}

기본적으로는 동일하지만 더 컴팩트합니다. 혼란스럽다면 버팀대 교체에 대한 자세한 정보를 찾아보세요.여기. sed 구문과 매우 유사합니다.

답변4

이는 Solaris 10 및 ksh88에서 작동하는 POSIX 호환 방식입니다.

print_underlined () {
  printf "%s\n%s\n" "$1" $(printf "%s\n" "$1" | sed "s/./-/g")
}

$ print_underlined "hello world"
hello world
-----------

관련 정보