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

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

4
задан 12 June 2019 в 11:06

2 ответа

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

  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
0
ответ дан 12 June 2019 в 11:06

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

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

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

Подробнее см. В расширение параметров .

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

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

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

Другие вопросы по тегам:

Похожие вопросы: