格式化输出:下划线

rah*_*hmu 4 shell solaris ksh

我编写了以下函数,ksh将它的第一个参数打印到屏幕上,并用适当的-字符数量加下划线:

print_underlined () {
    word=$1 
    echo $word

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

例子:

$ print_underlined foobar
foobar
------
$
Run Code Online (Sandbox Code Playgroud)

我想知道是否有一种更简单、更优雅的方式在屏幕上显示带下划线的单词。

为了记录我正在使用:

  • Solaris 10
  • ksh88

Gil*_*il' 6

您问题的核心是构建一个完全由下划线组成的字符串,该字符串与现有字符串的长度相同。在 bash、ksh 或 zsh 的最新版本中,您可以使用以下${VARIABLE//PATTERN/REPLACEMENT}结构构建此字符串:underlines=${word//?/_}. 但是这个构造在 ksh88 中不存在。

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

underlines=$(printf %s "$word" | tr -c '_' '[_*]')
Run Code Online (Sandbox Code Playgroud)

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

underlines=$(echo "$word" | tr -c '\010' '_')
underlines=${underlines%_}
Run Code Online (Sandbox Code Playgroud)

这里有一个稍微有点疯狂的方法,它不使用任何循环或外部程序,应该可以在任何 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
Run Code Online (Sandbox Code Playgroud)

一个更复杂的变体处理空格,但前提是没有任何连续的空格序列。我不认为你可以用这个技巧更进一步,因为空格字符的序列IFS总是折叠的。

set -f
unset IFS; set a $0    # split at whitespace
IFS=$*; set $*         # split into empty words
IFS=_; underlines=$*   # collect the empty
Run Code Online (Sandbox Code Playgroud)


jw0*_*013 5

在较新的 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
}
Run Code Online (Sandbox Code Playgroud)

对于完全不同的方法,请使用终端显示真实下划线的功能(如果可用):

tput smul; printf %s\\n "$word"; tput rmul
Run Code Online (Sandbox Code Playgroud)

当然,这种方法只有在您知道运行脚本的终端支持它时才有效。