同じ入力に対して異なるbash出力

同じ入力に対して異なるbash出力

予期しない動作が発生しましたbash。これは私の入力/出力です。

nepumuk@pc:~$  type URL
URL is a function
URL () 
{ 
    echo -e "${_//%/\\x}"
}
nepumuk@pc:~$  URL %2f
URL
nepumuk@pc:~$  URL %2f
/
nepumuk@pc:~$  URL %2F
/
nepumuk@pc:~$  type URL
URL is a function
URL () 
{ 
    echo -e "${_//%/\\x}"
}
nepumuk@pc:~$   URL %2f
URL
nepumuk@pc:~$  URL %2f
/
nepumuk@pc:~$  URL %2f
/
nepumuk@pc:~$  URL %2f
/
nepumuk@pc:~$    URL %2f
/
nepumuk@pc:~$   URL %2f
/

Bash関数ファイルの対応する部分は次のとおりです。

url() {
        : "${*//+/ }"
        echo -e "${_//%/\\x}"
}

export -f url

URL() {
        echo -e "${_//%/\\x}"
}

export -f URL

URLテスト中に変更があることを確認するために項目を変更しましたecho -e "${@//%/\\x}"。新しい端末(エミュレータ?)ウィンドウを開き、後者を使用すると

nepumuk@pc:~$  URL %2f
/usr/share/bash-completion/bash_completion
nepumuk@pc:~$  URL %2f
/
nepumuk@pc:~$  URL %2f
/

正確に再現できますが(そして希望の出力を提供するので前者を使用する)、説明をいただければ幸いです。

答え1

以前に実行したコマンドの最後の引数に変数bashを展開します($_他のものの間)。

url() {
   : "${*//+/ }"
   echo -e "${_//%/\\x}"
}

拡張が最初にno-opコマンド${*//+/ }に任意の引数として渡されるため、意味があります。:

これは+、位置引数のsを空白に置き換え、結果の文字列を間の最初の文字に関連付けることです($IFS引用時の一般的な効果)。$*

次に、2番目のコマンドは結果文字列を取得して%sに置き換え、\x結果をに渡しますecho

とオプションがすべて有効になっていないbash場合は、一部のエスケープシーケンスを拡張するために使用できるオプションのサポートが組み込まれています。したがって、対応するバイト値に置き換えられ、実際にURI%XXデコードが行われます。posixxpg_echoecho-e\xHH%HH

:最初のコマンドを削除すると、2番目のコマンドには、$_関数を呼び出す前に実行されるコマンドに渡された最後の引数が含まれます。

ここで関数を書いた人は、一時的な変数の使用を避けるためにこのトリックを使用したようです$_。しかし、これはコードが不必要に複雑になり、読みやすく理解しにくくなります。

uri_decode() {
  local IFS=' ' # make sure arguments are joined with spaces rather than
                # make some assumption on what $IFS may currently contain

  local tmp="$*" # positional parameters joined with spaces

  tmp=${tmp//+/ } # replace +s with spaces

  tmp=${tmp//[%]/\\x} # replace % with \\x. Using [%] instead of % for
                      # increased portability.

  printf '%b\n' "$tmp" # pass the result to printf for expanding of the \x
                       # sequences, avoiding echo whose behaviour depends on
                       # the environment, and would give incorrect results
                       # for strings like -Enee
}

+ - >空白変換を行わない変形が必要な場合は、そのtmp=${tmp//+/ }部分を削除してください。

関連情報