格式化输出:下划线

格式化输出:下划线

我编写了以下函数,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 中不存在此构造。

在任何 shell 中,您都可以使用tr它。符合 POSIX 标准的实现tr让您可以这样写:

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

我认为 Solaris 10 默认情况下符合 POSIX 标准tr,但可能有一个历史实现(与早期的 Solaris 版本兼容)。的历史实现tr可能不理解[x*]语法,但它们倾向于接受以下语法(POSIX 不保证),意思是“用 a 替换所有不是换行符的内容_”:

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

这里有一个有点疯狂的方法,它不使用任何循环或外部程序,并且应该在任何 Bourne shell 中工作(至少自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

在较新的 shell 中,您可以执行以下操作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

这是一种 POSIX 兼容方式,适用于 Solaris 10 和 ksh88:

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

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

相关内容