Невозможно перейти к (переданной) переменной в скрипте bash

Невозможно перейти к (переданной) переменной в скрипте bash

Я использую bash, чтобы получить некоторую информацию из audacious в conky для отображения (включая обложку альбома). Я получаю путь к каталогу музыкального файла из audacious, затем пытаюсь перейти в этот каталог, чтобы найти 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}"для расширениятолько.~

Насколько я могу судить,расширение тильдыявляется единственным типом расширения, которое необходимо выполнить для вывода audtool --current-song-tuple-data file-path. Более того, появляется только один конкретный случай нотации тильды: если путь, используемый Audacious, начинается с домашнего каталога пользователя, запустившего Audacious, эта часть пути заменяется на в ~выводе audtool. Посколькуaudaciousи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

Это вручную выполняет одно преобразование, которое может потребоваться. В частности, когда вывод audtoolначинается с ~, он заменяется на домашний каталог пользователя, полученный путем проверки значения переменной HOME. Когда вывод не начинается с ~, расширение не выполняется.

Обратите внимание, что этот подход, ${file_path/#~/$HOME}, будетнетбыло бы правильным, если бы оно использовалось как попытка симулировать все формы расширения тильды, поскольку оно выполняло бы неверные подстановки в форме ~username(и в некоторых других, более неясных формах). Однако, пока пути в выводе audtoolиспользуют только обозначение тильды в простом случае обозначения домашнего каталога текущего пользователя — что, как я полагаю, имеет место — тогда этот подходявляетсяуместно и правильно для этих путей.

Вот как это работает:

  • В общем,Баш будет расширяться ${parameter/pattern/string}в значение parameter, но счасть, которая соответствуетpatternзаменено на . Если ни одна часть не соответствует шаблону, используется stringточное значение .parameter
  • Если patternнаписано с ведущим #, его можно сопоставить только с самого начала значения parameter. (Кроме того, есть и другие символы #, которые имеют значение в этой позиции: a %потребует, чтобы шаблон сопоставлялся с самого началаконец, а a /приведет к тому, что шаблон будет сопоставлен и заменен столько раз, сколько он появляется, а не максимум один раз.)
  • ~не имеет особого значения в шаблоне и поэтому рассматривается буквально, как символ, подлежащий сопоставлению и замене.

Видетьрасширение параметрадля получения подробной информации.

Обратите внимание, что написанный мной код не делает ничего для обработки случая audtoolсоздания пустого вывода, как это происходит, когда в данный момент не воспроизводится песня (или, какСаймон Садлер упомянул, если есть ошибка). Однако он не прерывается на пустом выводе и не мешает последующей обработке. Так что если вы хотите охватить этот случай, вы все еще можете это сделать.

Наконец, я должен упомянуть, что я упустил из виду два различия, которые, по моему мнению, не имеют значения для вашего варианта использования:

  1. Поскольку audtoolпути взяты из Audacious, если бы вы попытались создать странную ситуацию, запустив Audacious от имени одного пользователя, а затем audtoolот имени другого (и каким-то образом настроили D-Bus так, чтобы это работало), то вам пришлось бы позаботиться о ~ссылке на домашний каталог другого пользователя, нежели пользователь, запустивший скрипт.
  2. Технически говоря, расширение тильды для текущего пользователя (которое происходит в оболочке само ~по себе или сразу после него /) не являетсядовольноэквивалентно "$HOME". Оболочки могут попытаться обработать странный случай, когда HOMEне установлено. Bash пытается обработать это и все равно выдать правильное расширение. Я сомневаюсь, что вас волнует различие для этой цели. См.расширение тильдыдля получения подробной информации.

решение2

Переназначение переменных file_pathне обязательно. Есть 2 признака того, что может произойти, что может нарушить скрипт:

  1. Переменная пуста, так как audtoolвозвращается ошибка
  2. Возвращает audtoolsкаталог, содержащий пробелы.
  3. audtoolвключает в себя ~для домашнего каталога

Вот предложение о том, как решить эти проблемы:

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здесь не поможет. Поэтому переменная, содержащая , ~должна быть выполнена без кавычек, чтобы быть расширенной (я обновил скрипт). Конечно, это можно сделать в одной строке...

# 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

Связанный контент