bash-скрипт: расширение {dir1, dir2, dir3} не работает должным образом от переменной для выбора случайного файла

У меня проблема с этим простым сценарием (выберите случайный файл):

#!/usr/bin/env bash
set -x
srcDir="/home/user/Desktop/wallPapers/{dir1,dir2,dir3}"
randomFile=$(find "$srcDir" -type f -iname "*.jpg" | shuf -n 1)
printf '[%s]\n' $randomFile
set +x

Проблема в том, что, хотя я могу набрать это в командной строке (и работает отлично):

find /home/user/Desktop/wallPapers/{dir1,dir2,dir3} -type f -iname "*.jpg"

Затем команды set для отладки bash (set -x и + x) сообщают мне, что по какой-то причине bash включает строку каталога с одинарными кавычками, а также заменяет двойные кавычки одинарными кавычками отмечает?

./script.sh
+ srcDir='/home/user/Desktop/wallPapers/{dir1,dir2,dir3}'
++ find '/home/user/Desktop/wallPapers/{dir1,dir2,dir3}' -type f -iname '"*.jpg"'
find: ‘/home/user/Desktop/wallPapers/{dir1,dir2,dir3}’: No such file or directory
+ randomFile=
+ printf '[%s]\n'
[]
+ set +x

Я понимаю, это то, что видит bash при запуске скрипта:

find '/home/user/Desktop/wallPapers/{dir1,dir2,dir3}' -type -iname '*.jpg'

И это вызывает сообщение «Нет такого файла или каталога», очень очень раздражает ... я не понимаю, почему он вставляет эти одинарные кавычки, я хочу использовать вместо них двойные кавычки, как в командной строке ... Может кто-нибудь объяснить, я был бы рад за это, спасибо!

6
задан 5 June 2019 в 21:44

3 ответа

Расширение фигурных скобок не происходит в пределах присваивания переменной, как объяснено здесь:

Почему префиксы тильды расширяются до назначения, а фигурные скобки - нет

В других контекстах кавычки также предотвратили бы расширение скобки.

Даже если вам удастся расширить srcDir до списка каталогов, повторное цитирование его в команде find приведет к тому, что он будет рассматриваться как один аргумент вместо 3 отдельных путей.

Вероятно, правильным способом сделать это в bash является использование массива:

#!/usr/bin/env bash
set -x
srcDir=("/home/user/Desktop/wallPapers/"{dir1,dir2,dir3})
randomFile=$(find "${srcDir[@]}" -type f -iname "*.jpg" | shuf -n 1)
printf '[%s]\n' "$randomFile"
set +x
11
ответ дан 5 June 2019 в 21:44

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

#!/usr/bin/env bash
printf '[%s]\n' "$(find /home/terdon/Desktop/wallPapers/{dir1,dir2,dir3} -type f -iname "*.jpg" | shuf -n 1)"

Или, если ваши имена файлов могут содержать символы новой строки:

#!/usr/bin/env bash
printf '[%s]\n' "$(find /home/terdon/Desktop/wallPapers/{dir1,dir2,dir3} -type f -iname "*.jpg" -print0| shuf -zn 1)"

Если вы хотите что-то, что может работать на произвольных каталогах и типах файлов попробуйте это:

#!/usr/bin/env bash

targetFilePattern="$1"
shift
declare -a targetDirs=("$@")
echo "find ${targetDirs[@]} -type f -iname '$targetFilePattern' | shuf -n 1"
randomFile=$(find "${targetDirs[@]}" -type f -iname "$targetFilePattern" | shuf -n 1)
echo "$randomFile"

Затем вы можете запустить его как:

printRandomFile '*jpg' /home/terdon/Desktop/wallPapers/{dir1,dir2,dir3}

Или даже

printRandomFile '*jpg' /home/terdon/Desktop/wallPapers/{dir1,dir2,dir3,'a dir with a space'}
4
ответ дан 5 June 2019 в 21:44

Расширение фигурных скобок не выполняется внутри двойных кавычек. Есть дублирующий вопрос относительно этого где-то. Кроме того, используйте флаг -printf для поиска, выполнять подстановку команд не нужно, поэтому вы можете сделать это

find /home/user/Desktop/wallPapers/{dir1,dir2,dir3} -type f -iname "*.jpg" -printf '[%f]\n' | shuf -n1
3
ответ дан 5 June 2019 в 21:44

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

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