解析したい変数の周りの引数の拡張をどのように防ぐのですか?

解析したい変数の周りの引数の拡張をどのように防ぐのですか?

編集する:

もっと読む前に重要な注意:コサロナンダの答え、彼が私が使っている他のスクリプトのバグを指摘したので、私の質問は今役に立たない。このバグは今修正され、私が説明した次のエラーはもう発生しません!

$extensionの値が拡張される2つの問題がコードにあります。
2番目の問題は関数自体にあります。


長い話を短く

質問を書き始めたときに詰まったが効果的な解決策が見つかりました。シェルノグローブ)、しかしまだ「書くことはできますか?」という質問があります。

この質問に対する答えが出てきたと確信していますが、bashの拡張に関する何百ものトピックに陥っています。

私の場合は次のようになります。

  • スクリプトを実行したいと思います(正規表現を受け入れるオプションパターンを使用しているとしますffmpeg)。-pattern_type glob -i*.JPG
  • 議論する(言うなら*.JPG
  • 変数の引数(言い換えれば$extension
  • スクリプトパラメータの変数(言えば$1
  • しかし、私は欲しくない基本的にシェルを$extension同様のパターンに拡張したい*.JPG

これはすべてスクリプト内で行われますscript.sh

したがって、ユーザーは次のことを実行できます。

script.sh 'JPG' ; # where $1='JPG'

注: をscript.sh連結して、*.より$1多くの最終正規表現を取得します。*.JPG

私は(ここから)読むhttps://stackoverflow.com/a/11456496/912046ffmpeg引数を受け取る前にシェル拡張が発生します(ffmpegシェル拡張が発生したことを知らずに)。

${extension}私はさまざまな方法で引用符、二重引用符、またはバックスラッシュを試しましたが、成功しませんでした。
以下はいくつかの試みです。

ffmpeg ... "${extension}"

原因:(ffmpeg 1.jpg 2.jpg [...]拡張発生)

ffmpeg ... ${extension}

同じ

ffmpeg ... '${extension}'

検索パターンのため、一致するファイルはありません${extension}(変数名は文字通り使用されます)。

extension="\'${extension}\'" ; # wrapping the single quotes (preventing expansion) directly in variable
ffmpeg ... ${extension}

'*.jpg'一重引用符を含む検索パターンのため、一致するファイルはありません。

ffmpeg ... \"${extension}\"

同じですが検索中"*.jpg"(二重引用符を含む)

最後に、Shell noglobオプションを使用して成功しました。
以下は興味深いコマンドです。

set -f ; # disable glob (prevent expansion on '*.jpg')
ffmpeg -pattern_type glob -i ${extension} movie.mp4 ;
set +f ; # restore, but what if glob was already disabled? I should not restore it then?

しかし、疑問に思いますが、解析したい変数でスクリプトパラメータが拡張されるのを防ぐための別の方法がありますか? (それで、変数が解析/置換されなくなるように拡張を防ぐ方法(一重引用符を使用)を知っています。)

次のようになります。 (しかし、文字列接続を読みました。セキュリティ上の理由から挿入を避ける必要があります。)

ffmpeg '${extension}'
       ||           | 3
       || 2
       | 1

どこ:

  • 1:最終結果に対して一重引用符がオンになります。ffmpeg '*.jpg'
  • 2:extension変数が注入され解析されます。.jpg
  • ffmpeg3:手動で作成したように、パラメータを受け取るために一重引用符を閉じます。'*.jpg'

編集:拡張変数を割り当てる方法の説明に従ってください。

local extension="${2}" ;
echo $extension ;
extension="${extension:=jpg}" ; # Default on "jpg" extension
# wrapp extension type in single quotes + prefix with "*."
extension="*.${extension}" ;

次に、次のように使用します。

runprintcommand ffmpeg -loglevel verbose -pattern_type glob -i ${extension} "$movieName" ;

runprintcommand関数/スクリプトは次のとおりです。

function runprintcommand() {
    echo "Command to run: (Note: '\\' escape character may not be printed)" ;
    echo "$*" ;
    $* ;    
}

ベストアンサー1

  • 引用符を持たない変数は、変数の拡張、単語の区切り(デフォルトでは空白、タブ、および改行)を経て、生成された各単語は順番にファイル名の生成(ワイルドカード指定)を経ます。
  • 二重引用符で囲まれた変数は値が拡張されますが、シェルは拡張値をトークン化したりワイルドカードとしてマークしたりしません。
  • 一重引用符内の変数はまったく拡張されません。

例:

$ ls
script.sh
$ var='* *'
$ echo $var
script.sh script.sh
$ echo "$var"
* *
$ echo '$var'
$var

コードには、の値を$extension含むglobパターンに拡張され、globパターンが内部的にファイル名(それ自体のglob拡張にそのまま渡したいffmpeg -i)と早期に一致させる2つの問題があります。

最初は関数呼び出しです。

runprintcommand ffmpeg -loglevel verbose -pattern_type glob -i ${extension} "$movieName" ;

ここには${extension}何も引用されていないので本当にその値から発生するファイル名のグロービングを取得します(トークン化および)。

2番目の問題は関数自体です。

function runprintcommand() {
    echo "Command to run: (Note: '\\' escape character may not be printed)" ;
    echo "$*" ;
    $* ;    
}

ここでは、関数呼び出しで二重引用符を使用しても、$*再び(値を単語で除算して)グローバルを拡張する引用符で囲まれていない部分を使用しています。${extension}

$*"$@"bareの代わりに(二重引用符を含む)を使用してください。これは次のように拡張されます。一人で引用関数の位置パラメータです。

"$@"これがとの違いです"$*"

  • "$*"はい一重引用符で囲まれた文字列。これは通常、パラメーター付きのコマンドを実行するためには使用できません。
  • "$@"はい二重引用符で囲まれた単語のリスト。パラメーターを使用してコマンドを実行するために使用できます。

おすすめ記事