Вопрос или проблема
Я хочу передать список путей к файлам, полученный одной командой (программа KDE baloosearch6
), в качестве аргументов командной строки другой команде (программа для просмотра изображений KDE gwenview
). Вечная проблема в том, что пути к изображениям содержат пробелы, поэтому мне нужно заключать их в кавычки, например: gwenview '/path/to/my first file' '/path to/another file'
. У программ нет опций -print0
/-0
.
Claude AI дал мне однострочное решение для этого:
baloosearch6 foobar | sed "s/.*/'&'/" | tr '\n' ' ' \
| xargs gwenview
но должен быть лучший способ, например, обработка массива путей к файлам. Как правильно собрать массив строк в zsh дает магию zsh для сбора строк вывода в массив:
files=("${(@f)$(baloosearch6 foobar)}")
но теперь мне нужно превратить массив путей к файлам обратно в заключенные в кавычки параметры командной строки. Я прочитал главу о подстановках из “Руководства пользователя по Z-Shell” и не нашел ответа. Возможно, мне стоит поработать с IFS
и подобными вещами.
В идеале я хочу одну команду/функцию make_cli_args, которая превращает вывод одной команды в заключенные в кавычки аргументы для другой. (Почему это так сложно?)
Если у вас есть массив и вы просто хотите передать его элементы в неизменном виде команде, достаточно использовать $array
в zsh или "${array[@]}"
(в кавычках!) в Bash/ksh. Первый вариант пропускает пустые элементы, однако "${array[@]}"
работает в любом случае:
zsh:
% l=("foo * bar" '' $'new\nline')
% printf '<%s>\n' $l
<foo * bar>
<new
line>
% printf '<%s>\n' "${l[@]}"
<foo * bar>
<>
<new
line>
Bash:
$ l=("foo * bar" '' $'new\nline')
$ printf '<%s>\n' "${l[@]}"
<foo * bar>
<>
<new
line>
С другой стороны, если вам нужно передать элементы массива в оболочку для выполнения в качестве командной строки, вам нужно будет правильно заключить их в кавычки. Это может произойти, если вам нужно встроить значения в сценарий оболочки, или запустить их с помощью eval
(по какой-либо причине), или передать их через ssh
.
Здесь вы можете использовать printf %q
в Bash или zsh, или модификатор (q)
в zsh.
Функция printf %q
в Bash обычно использует обратные слеши, так что вывод выглядит некрасиво, но это должно работать (команда echo
добавляет перенос строки в конце):
$ printf '%q ' "${l[@]}"; echo
foo\ \*\ bar '' $'new\nline'
Функция (qqqq)
в zsh использует кавычки $'...'
, что выглядит лучше:
% printf '%q ' "${l[@]}"; echo
foo\ \*\ bar '' new$'\n'line
% printf "%s " ${(qqqq)l}; echo
$'foo * bar' $'' $'new\nline'
В любом случае я бы постарался избегать вставки данных в кавычках внутрь кода. Обычно это вызывает сложности и имеет множество крайних случаев.
В большинстве случаев с именами файлов достаточно передать их в сыром виде, по одному на строку, и считать их в массив. (И убедитесь, что в именах файлов нет переносов строк, или проверьте их и сообщите об этом.)
Ответ или решение
Для решения задачи передачи списка пути к файлам, полученного от одной команды (в данном случае программы KDE baloosearch6
), в качестве аргументов командной строки для другой команды (это программа просмотра изображений KDE gwenview
), необходимо учитывать, что пути к файлам могут содержать пробелы. Это усложняет процесс, так как необходимо правильно обрабатывать эти пробелы, чтобы передать корректные аргументы.
Подход с использованием массива в Zsh
Одним из эффективных способов решения данной задачи в Zsh является использование массивов для хранения путей к файлам, а затем их преобразование в соответствующий формат для передачи как аргументы другой команде.
1. Сбор путей в массив
Первым шагом является сбор путей к файлам в массив. Это можно сделать, используя следующий синтаксис:
files=("${(@f)$(baloosearch6 foobar)}")
baloosearch6 foobar
— это команда, которая возвращает список путей к файлам.@f
— это расширение, которое обрабатывает выходные данные как строки, разбивая их по символу новой строки.
2. Преобразование массива в строку с аргументами
Следующим шагом будет преобразование массива путей к файлам в строки, которые могут быть переданы как аргументы команде gwenview
. Удобным способом является использование модификатора (qqqq)
для автоматического экранирования строк:
gwenview $files
Если требуется более явная обработка для создания строк, которые можно использовать и в других контекстах, можно использовать команду printf
с форматом:
gwenview $(printf "%q " "${files[@]}")
Тем не менее, использование $(printf "%q ")
может привести к не самым читаемым результатам, так как эта команда экранирует специальные символы.
3. Реализация функции make_cli_args
Чтобы создать единую функцию make_cli_args
, которая будет обрабатывать команды, можно использовать следующий код:
make_cli_args() {
local files=("${(@f)$(baloosearch6 $1)}")
gwenview "${files[@]}"
}
- Эта функция принимает один аргумент (например,
foobar
для поиска) и передаёт полученные пути вgwenview
.
Альтернативный подход в Bash
Если вы работаете в Bash, аналогичный процесс может быть реализован с использованием синтаксиса массива и printf
:
make_cli_args() {
local files=($(baloosearch6 "$1"))
gwenview "${files[@]}"
}
Однако обратите внимание, что в Bash для обработки пробелов в именах файлов необходимо использовать следующий подход, чтобы избежать искажений:
printf '%q ' "${files[@]}"
Заключение
В результате, грамотно построенная функция make_cli_args
позволяет изящно и эффективно передавать пути к файлам в другую команду, минимизируя возможные ошибки, связанные с неправильной интерпретацией пробелов и спецсимволов. Этот подход высокоэффективен и может быть адаптирован под другие команды и сценарии в зависимости от ваших потребностей.