フォーマットされた出力:下線

フォーマットされた出力:下線

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

おすすめ記事