はじめに。私はこの言語でC
このprintf
関数が次のことを行うことができることを知っています:
printf('%2$s %2$s %1$s %1$s', 'World', 'Hello');
出力:Hello Hello World World
しかし、この機能はGNU Bashではサポートされていないようです。
printf '%2$s %2$s %1$s %1$s' 'World' 'Hello'
出力:bash: printf: $': invalid format character
私もlocalを使ってみました/usr/bin/printf
。
/usr/bin/printf '%2$s %2$s %1$s %1$s' 'World' 'Hello'
出力:/usr/bin/printf: %2$: invalid conversion specification
C
Bashで動作を取得する方法は?ありがとうございます。
編集する:
この動作が不思議であり、パラメータの順序を変更する回避策を受け入れることができません。フォーマット文字列のみを使用しても機能します。
編集する:
たとえば、GNU Bashのソースコードの国際化を考えてみましょう。この機能がなければ非常に不可能です。
答え1
bash
君はこれと競争できないprintf
ユーティリティのPOSIX仕様サポートされていません。パラメータを手動で並べ替える必要があります。
printf
そして(またはprint -f
)組み込み関数はksh93
それをサポートしますzsh
:
$ printf '%2$s%1$s\n' a b
ba
GNUawk
またはGNUperl
もこれをサポートしているため、どちらかがインストールされている場合は、次の関数でbash
上書きできます。printf
printf() { zsh -c '"$0" "$@"' printf "$@"; }
または:
printf() { ksh93 -c '"$0" "$@"' printf "$@"; }
gawk
使用するか、より多くの努力が必要です。そのまま渡すことができず、シーケンスを拡張せず(二重引用符内にコードとして逐語的に渡されない限り)、サポートしていないperl
からです(シミュレーション用ユーティリティの拡張)。 V)。gawk
ARGV
gawk
perl
\x
%b
printf
echo
答え2
printfを関数にオーバーライドすると、他のプロセスを呼び出すことなくbashがこれを行うことができます。
printf() { # add support for numbered conversion specifiers
local -a args
local opt=
case $1 in
-v) opt=-v$2; shift 2;;
-*) opt=$1; shift;;
esac
local format=$1; shift
while [[ $format =~ ((^|.*[^%])%)([0-9]+)\$(.*) ]]
do
args=("${!BASH_REMATCH[3]}" "${args[@]}")
format=${BASH_REMATCH[1]}${BASH_REMATCH[4]}
done
let ${#args[@]} && set -- "${args[@]}"
builtin printf $opt "$format" "$@"
}
これは、書式文字列の番号付き変換指定子を番号なし変換指定子に置き換えると同時に、数値を使用して変更されたパラメータリストのパラメータを選択することによって行われます。数値変換指定子がない場合、printf 組み込み関数は関数の引数をそのまま表示します。驚くべき動作がほとんどない簡単な交換でなければなりません。
bash正規表現のマッチングは貪欲なので、新しい引数リストを作成するステートメントの順序は驚くことができます。したがって、whileループが見つかるたびに新しい引数を追加する代わりに、args []配列の前にプッシュする必要があります。数値変換指定子は、書式文字列に残っている最後の指定子になります。
また、変換指定子を含む書式文字列よりも多くの引数が渡された場合、数値指定子に対応しない引数があると、printf 組み込みで通常行われている書式文字列のリサイクルは発生しません。ただ無視してください。 POSIXが番号付き変換指定子と番号なし変換指定子の混合を定義されていないと説明していることを考慮すると、これは合理的だと思います。