![格式化输出:下划线](https://linux22.com/image/43172/%E6%A0%BC%E5%BC%8F%E5%8C%96%E8%BE%93%E5%87%BA%EF%BC%9A%E4%B8%8B%E5%88%92%E7%BA%BF.png)
我编写了以下函数,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
-----------