web-dev-qa-db-ja.com

bashの配列拡張に複数文字の区切り文字を使用するにはどうすればよいですか?

私は質問を(私が信じる)最も単純なケースに減らしています。スクリプトがあるとしましょうmyscript.sh次の内容で:

#!/bin/bash
IFS='%20'
echo "$*"

次のようにコマンドを実行すると、出力は次のようになります。

me@myhost ~ $ ./myscript.sh fee fi fo fum
fee%fi%fo%fum

bashのマニュアルページで説明されているように、これは予想される動作です。

   *      Expands  to  the positional parameters, starting from one.  When
          the expansion occurs within double quotes, it expands to a  sin-
          gle Word with the value of each parameter separated by the first
          character of the IFS special variable.  That is, "$*" is equiva-
          lent to "$1c$2c...", where c is the first character of the value
          of the IFS variable.  If IFS is unset, the parameters are  sepa-
          rated  by  spaces.   If  IFS  is null, the parameters are joined
          without intervening separators. 

しかし、私が取得したいのは出力です:

fee%20fi%20fo%20fum

したがって、単一の文字ではなく、複数文字の区切り文字フィールドを使用します。

bashにネイティブなこれを行う方法はありますか?


更新:

以下のmikeservからのデータと、 printfがechoよりも優れている理由 の記述に基づいて、私は次のことを行うことになりました(上記の例のように最も単純なケースに縮小されました)。

#!/bin/bash
Word="$1"
shift
if [ "$#" -gt 0 ] ; then
    Word="$Word$(printf '%%20%s' "$@")"
fi
printf '%s\n' "$Word"
unset Word
3
Wildcard

printfは、出力時にそれに続く各引数にフォーマット文字列を適用します。これはbashシェルに組み込まれており、引数のリストに区切り文字列を適用するために使用できます。

例えば:

printf %s:delimit: arg1 arg2 arg3

arg1:delimit:arg2:delimit:arg3:delimit:

重要なのは、printfは引数の最後にフォーマット文字列を適用しないstopであるため、最後の1つには区切り文字が追加されます。これは、場合によっては処理できます。

printf %b:delimit: \\0150 \\0145 \\0171\\c

h:delimit:e:delimit:y

printfは、Cと8進数のエスケープを特定の種類の形式の%bytesとして解釈し、%b形式では、特定の時点で出力を\cutします。これが理由です。 printfは、フォーマット文字列が示すように、上記のyの後に:delimit:文字列を続けません。

したがって、すべての引数を文字通りに解釈する必要がある場合および末尾の区切り文字を使用しない場合は、引数リスト自体の中で問題に対処する必要があります。

set -- arg1 arg2 arg3
for arg do shift
    set -- "$@" :delimit: "$arg"
done; shift
printf %s "$@"

arg1:delimit:arg2:delimit:arg3
5
mikeserv

zshでは、j:string:パラメータ拡張フラグ を使用できます。

set -- fee fi fo fum
delims=%20
print -rl ${(j:$delims:)@}
2
cuonglm