kshパラメータ拡張:/を-に置き換える

kshパラメータ拡張:/を-に置き換える

私がこれを持っているとしましょう:

str="@test/string"
echo $str
@test/string
echo ${str#@}
test/string

期待どおりに動作しますが、

echo ${str//\//-}
ksh: ${str//\//-}: bad substitution

失敗する。 (@test-string 期待)

このような文字を変更または変更する正しい方法は何ですか?


echo $KSH_VERSION
KSH version @(#)PD KSH v5.2.14 99/07/13.2

答え1

${var//pattern/replacement}はksh93演算子ですが、pdkshは最後のバージョンksh88i1である元のkshのレプリカとして使用されます。 pdkshはプロジェクトとして中断されましたが、shOpenBSDやMirBSDを含む少数のBSDの一部としてまだ存在しています。 mkshとも呼ばれるMirBSD sh / kshはポータブルシェルとしても維持されており、多くのLinuxディストリビューション(Androidでも利用可能sh)で利用できます。 2008 R33 リリースでは ksh93 演算子が追加されました。

POSIXlyでは、変数の1つの文字を別の文字に置き換えるためにtransliteratorユーティリティを使用できますが、stdinで変数の内容を提供し、stdoutから結果を取得する必要があります。

newstr=$(printf %s "$str" | tr / -; echo .)
newstr=${newstr%.}

.\n(これはコマンド置換が末尾の改行を削除するという事実を説明するために追加されました)。

別のコマンドを実行したくない場合は、分割+glob演算子を使用することもできます。

IFS=/ # split on /
set -o noglob # disable the glob part
set -- $str'' # split+glob by leaving $str unquoted
IFS=. # join on . in "$*"
newstr="$*"

1 ksh93は以前のバージョンと完全に互換性がありませんが、多くの新機能を備えた書き換えですが、その多くはまだ実験的で、2000年代にコードがオープンソースとしてリリースされる前にはほとんど使用されていません。

答え2

シェルは、pdksh前述の非標準パラメータの代入なしでOpenBSDなどの新しいユーザーのためのデフォルトシェルです。

一部のパターンと重複しないすべての一致を新しい文字列に置き換えるには、次のようにしますsed

str=$( printf '%s\n' "$str" | sed 's/PATTERN/REPLACEMENT/g' )

PATTERNこれはPOSIXの基本正規表現として使用され、特別な方法で解釈される他の文字列だけでなくエスケープする必要がREPLACEMENTあり、コマンド置換は文字列の末尾から末尾の改行文字を削除します。&\1sed

例:

$ str=@title/section1/section2
$ str=$( printf '%s\n' "$str" | sed 's/\//-/g' )
$ printf '%s\n' "$str"
@title-section1-section2

この場合、1文字だけを置き換える場合sedに置き換えるy/\//-/か、sedコマンド全体をtrcommandに置き換えますtr / -

シェルループを作成することもできます。

while true; do
    case $str in
        *PATTERN*)
            str=${str%%PATTERN*}REPLACEMENT${str#*PATTERN}
            ;;
        *)
            break
    esac
done

このコードにはPATTERNシェルパターン(「ファイル名グロービングパターン」)があります。コードは、一致する項目がなくなるまで、文字列に最初に現れるパターンを代替文字列に繰り返し置き換えます。ループの存在により、後続の反復で以前に挿入された置換文字列で置換を実行しないという保証はありません。

例:

$ str=@title/section1/section2
$ while true; do case $str in (*/*) str=${str%%/*}-${str#*/} ;; (*) break; esac; done
$ printf '%s\n' "$str"
@title-section1-section2

答え3

確かにより良い方法ですが:

$(echo "$str" | tr '/' '-')

関連情報