bash スクリプトで (渡された) 変数に cd できない

bash スクリプトで (渡された) 変数に cd できない

私は bash を使用して、audacious から conky に情報を取得して表示しています (アルバム アートを含む)。audacious から音楽ファイルのディレクトリへのパスを取得し、そのディレクトリに cd して folder.jpg を見つけようとします。見つかった場合は、表示の準備をします。残念ながら、「適切な形式の」パス名に頼ることはできません。ターミナルからはどれも問題はありませんが、bash が行う評価は... 二重スペース ( ) ' / やおそらく他のものでも詰まりますが、現在の設定では問題なく処理されているようです。関連する関数は次のとおりです。

GetArt ()
{
    file_path=`audtool --current-song-tuple-data file-path` # get the path to the song
    file_path=$(eval echo "${file_path}")                   # pre-expand to full path
    cd "${file_path}"
    if [[ ! -e "folder.jpg" ]];                             # if no art work found
    then
        cp ~/Work/vinyl.png /tmp/cover.png              # put in placeholder
    else
        convert "${file_path}""/folder.jpg" -resize 120x120 /tmp/cover.png # ready for showing
    fi
}

何かアイデアはありますか、それともワイヤーブラシを取り出して「C」コンパイラから錆を取り除く方が簡単でしょうか?

二重引用符、一重引用符、バッククォート、さらには次のような構文も試しました。

code=$code \"\$filename\""

しかし、まだ何も正しく動作していないようです。幸いにも、代わりに「アートが見つかりません」という代替画像が表示されるので、うまく失敗しますが、次の曲またはアルバムまで、stderr 全体にデータが吐き出されることがあります。

答え1

file_path="${file_path/#~/$HOME}"拡張するために使用できますただ~

私の知る限り、チルダ展開の出力に対して実行する必要がある唯一の種類の展開です。さらに、チルダ表記の特定のケースは1つだけです。Audaciousが使用しているパスがAudaciousを実行しているユーザーのホームディレクトリで始まる場合、パスのその部分は の出力audtool --current-song-tuple-data file-pathで に置き換えられます。~audtoolaudaciousそしてaudtoolman ページではこの点は明確に説明されていませんが、チルダ展開の形式audtoolでプレフィックスされた出力パスを取得しようとしました~usernameが、幸いなことに、それすら行われないようです。「幸いなことに」と言うのは、状況が非常に単純であることを意味するからです。

このコマンドの出力に必要な変換は、audtool先頭を~ユーザーのホームディレクトリのパスに置き換えることだけなので、スクリプトにその展開だけを行うコードを記述するだけで、パスは変更されません。再生するオーディオファイルのファイル名には、シェルによって特別に扱われる文字が含まれている可能性があることがわかりました。他の人が命名したファイルを再生するとセキュリティ上の脆弱性が生じる可能性もあるあなたのスクリプトでシェルに任意の信頼できないテキストを実行させたり展開させたりしないようにすることで、この問題を完全に回避できます。

自分自身を成長させる方法はいくつかあります~。私の提案は次のとおりです。

file_path="$(audtool --current-song-tuple-data file-path)"  # might need tilde expansion
file_path="${file_path/#~/$HOME}"  # do the tilde expansion, if needed

これにより、必要になる可能性のある 1 つの変換が手動で実行されます。具体的には、 の出力がaudtoolで始まる場合~、 はそれを、変数の値をチェックして取得したユーザーのホーム ディレクトリに置き換えますHOME。出力が で始まらない場合~、展開は実行されません。

このアプローチでは${file_path/#~/$HOME}ないチルダ展開のあらゆる形式をシミュレートする試みとして使用された場合、正しいとは言えません。なぜなら、その~username形式(および他のより不明瞭な形式)では誤った置換が行われるからです。ただし、出力のパスが現在のユーザーのホームディレクトリを指定する単純な場合にのみチルダ表記を使用する限り(audtoolこれが当てはまると思います)、このアプローチはそれらのパスに適切かつ正しいもの。

仕組みは次のとおりです。

  • 一般的に、バッシュは拡大する ${parameter/pattern/string}の値に代入しますparameterが、一致する部分patternに置き換えられますstring。パターンに一致する部分がない場合は、 の正確な値がparameter使用されます。
  • patternが で始まる場合#、 の値の先頭からのみ一致できます。(この位置では、parameter以外にも意味のある文字があります。 は、パターンが の先頭から一致することを必要とします。#%終わり、および a を使用する/と、パターンは最大 1 回ではなく、出現する回数だけ一致して置換されます。
  • ~パターンでは特別な意味を持たないため、一致して置換される文字として文字通り扱われます。

見るパラメータ拡張詳細については。

私が書いたコードは、audtool現在再生中の曲がない場合(または、サイモン・サドラーは、エラーがある場合)。ただし、空の出力で中断したり、その後の処理の邪魔になったりすることはありません。そのため、そのケースをカバーしたい場合は、引き続き可能です。

最後に、ここでは、あなたのユースケースにとって重要ではないと思われる 2 つの違いについて簡単に説明しました。

  1. audtoolのパスは Audacious から取得されるため、Audacious をあるユーザーとして実行し、audtool別のユーザーとして実行するという奇妙な状況を試みる場合 (そして、何らかの方法で D-Bus を構成してそれが機能する場合)、スクリプトを実行しているユーザーとは異なるユーザーのホーム ディレクトリを参照することに注意する必要があります~
  2. 技術的に言えば、現在のユーザーに対するチルダ展開(シェル内で~単独で、または直後に が続く場合に発生する/)はとてもと同等です"$HOME"。シェルは、が設定されていない奇妙なケースを処理しようとする場合がありますHOME。Bash はこれを処理しようとし、正しい展開を生成します。ただし、この目的のためにこの区別を気にする人はいないと思います。チルダ展開詳細については。

答え2

変数の再割り当てはfile_path必要ありません。スクリプトを壊す可能性がある兆候が 2 つあります。

  1. 変数は空です。audtoolエラーが返されるからです。
  2. audtools空白を含むディレクトリを返します。
  3. audtool~ホームディレクトリのincludes

これらの問題に対処する方法に関する提案は次のとおりです。

GetArt ()
{
    file_path="$(audtool --current-song-tuple-data file-path)"
    file_path="$(readlink -f "$(bash -c "echo $file_path")")"
    if [[ ! -d $file_path ]]; then
        echo "error: $file_path does not exists"
        exit 1
    fi
    folder_jpg="$file_path/folder.jpg"
    if [[ ! -e "$folder_jpg" ]]; then
        cp ~/Work/vinyl.png /tmp/cover.png
    else
        convert "$folder_jpg" -resize 120x120 /tmp/cover.png
    fi
}

"$(command)"、フォルダ名内の空白文字を処理します (存在する場合)。cd必要がない場合は、スクリプト内で使用しないでください。返される文字列がディレクトリであるかどうかを確認することは、常に良い考えです。絶対パスで作業する方がほとんどの場合より適切であり、間違ったフォルダでコマンドが実行されることを防ぎます。

~bash での展開に関する注意:

の展開は~bash によって処理されるため、readlink -fここでは役に立ちません。したがって、 を含む変数は、~展開されるために引用符なしで実行する必要があります (スクリプトを更新しました)。もちろん、これは 1 行で処理できます...

# expansion from current bash
$ set -x; readlink -f ~; set +x
+ readlink -f /home/user
/home/user
+ set +x

# expansion will not work, with quoted ~
$ set -x; readlink -f '~'; set +x
+ readlink -f '~'
/home/user/~
+ set +x

# expansion from un-quoted ~ with sub-shell
$ set -x; readlink -f "$(bash -c "echo ~")"; set +x
++ bash -c 'echo ~'
+ readlink -f /home/user
/home/user
+ set +x

関連情報