Почему эти аргументы фильтра rsync не работают в bash при передаче в виде массива?

Вопрос или проблема

Почему эта команда rsync работает, когда я ввожу ее буквально, но не работает, когда я создаю ее из переменных?

Вот переменные — сначала опции, которые я передаю в rsync в виде массива:

$ echo "${options[@]}"
-av --prune-empty-dirs -f "- *.flac" -f "- *.WMA" -f "- *.wma" -f "- *.ogg" -f "- *.mp4" -f "- *.m4a" -f "- *.webm" -f "- *.wav" -f "- *.ape" -f "- *.zip" -f "- *.rar"

$ echo ${options[6]}
-f

$ echo ${options[7]}
"- *.wma"

Затем исходная директория, из которой rsync должен скопировать файлы:

$ echo "\"$dir/\""
"/media/test/Ahmad Jamal Trio/Live at the Pershing/"

И целевая директория, в которую rsync должен скопировать файлы:

$ echo "\"$target_dir\""
"/home/test/mp3/Ahmad Jamal Trio/Live at the Pershing/"

Собираем все вместе:

$ echo "${options[@]}" "\"$dir/\"" "\"$target_dir\""
-av --prune-empty-dirs -f "- *.flac" -f "- *.WMA" -f "- *.wma" -f "- *.ogg" -f "- *.mp4" -f "- *.m4a" -f "- *.webm" -f "- *.wav" -f "- *.ape" -f "- *.zip" -f "- *.rar" "/media/test/Ahmad Jamal Trio/Live at the Pershing//" "/home/test/mp3/Ahmad Jamal Trio/Live at the Pershing/"

Все выглядит так, как должно. И действительно, это работает, если вы вводите команду буквально, как это:

$ rsync -av --prune-empty-dirs -f "- *.flac" -f "- *.WMA" -f "- *.wma" -f "- *.ogg" -f "- *.mp4" -f "- *.m4a" -f "- *.webm" -f "- *.wav" -f "- *.ape" -f "- *.zip" -f "- *.rar" "/media/test/Ahmad Jamal Trio/Live at the Pershing/" "/home/test/mp3/Ahmad Jamal Trio/Live at the Pershing/"
./
Ahmad Jamal Trio - Live at the Pershing - 01 - But Not for Me.mp3
Ahmad Jamal Trio - Live at the Pershing - 02 - Surrey With The Fringe On Top.mp3
Ahmad Jamal Trio - Live at the Pershing - 03 - Moonlight In Vermont.mp3
Ahmad Jamal Trio - Live at the Pershing - 04 - Music, Music, Music.mp3
Ahmad Jamal Trio - Live at the Pershing - 05 - No Greater Love.mp3
Ahmad Jamal Trio - Live at the Pershing - 06 - Poinciana.mp3
Ahmad Jamal Trio - Live at the Pershing - 07 - Wood'yn You.mp3
Ahmad Jamal Trio - Live at the Pershing - 08 - What's New.mp3
AlbumArtSmall.jpg
AlbumArtLarge.jpg
Folder.jpg

sent 43,194,376 bytes  received 285 bytes  28,796,440.67 bytes/sec
total size is 43,182,454  speedup is 1.00

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

$ rsync "${options[@]}" "\"$dir/\"" "\"$target_dir\""
Unknown filter rule: `"- *.flac"'
rsync error: syntax or usage error (code 1) at exclude.c(902) [client=3.1.2]

Часть ваших фильтров rsync и исходные и целевые директории заключены в кавычки с дополнительными экранированными кавычками.
Удалите экранированные кавычки, и это должно сработать:

options=(
  -av --prune-empty-dirs 
  -f "- *.flac" 
  -f "- *.WMA" 
  -f "- *.wma" 
  -f "- *.ogg" 
  -f "- *.mp4" 
  -f "- *.m4a" 
  -f "- *.webm" 
  -f "- *.wav" 
  -f "- *.ape" 
  -f "- *.zip" 
  -f "- *.rar"
)
dir="/media/test/Ahmad Jamal Trio/Live at the Pershing"
target_dir="/home/test/mp3/Ahmad Jamal Trio/Live at the Pershing"
rsync "${options[@]}" "$dir/" "$target_dir"

Я убрал завершающие косые черты из переменных dir и target_dir, / уже добавляется к $dir в вызове rsync.

Другой способ — использовать модификаторы расширения переменных оболочки bash. Не уверен, что они существуют во всех оболочках?

Эти модификаторы: @U @l @E @Q @K @k @A @a @P, смотрите руководство по bash или sh для получения дополнительной информации. Нам здесь нужен @E

например, для rsync — который, как я обнаружил, является очень требовательным

#!/bin/bash

trap "set +x +v" RETURN

set +x +v +e

RSYNC=/home/user/.local/bin/rsync

declare -a OPS
OPS=()

OPS+=(-rtpogAXlHDU -cvzxsh)
OPS+=("--rsync-path=${RSYNC}")
OPS+=(--filter '+r /mnt/sde/')
OPS+=(--filter '- *~')

SRC="https://unix.stackexchange.com/questions/550449/[email protected]:work'
DST='/mnt/sde/backup'

clear

echo ${RSYNC} "${OPS[@]@E}" "${SRC@E}" "${DST@E}"
echo -e "-----\n\n"

set -v -x
${RSYNC} "${OPS[@]@E}" "${SRC@E}" "${DST@E}"

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

  • Способ добавления элементов массива с помощью += может сделать код компактным, так как пробелы являются разделителями между элементами (как в первом примере)
  • Токен «весь массив» [@] расширяет весь массив в аргументы.
  • Имейте в виду, что альтернативный [*] ведет себя по-другому, он соединяет список через пробелы, а не как отдельные аргументы.
  • Существует подвох, так как обработчик синтаксического анализа командной строки в некоторых программах может спутать их, и иногда приходится использовать «неправильный».
  • Расширение в двойных кавычках "${...}" гарантирует, что пробелы в аргументах не разделятся после расширения (мое общее правило: начинайте с двойного заключения в кавычки каждого расширения переменной bash)
  • Модификаторы @E в конце ${...@E} сообщают bash о необходимости экранировать любые символы во время расширения, которые в противном случае изменили бы вывод. (в этом случае одиночные кавычки и пробелы), хотя это также должно работать для таких расширенных символов, как юникод. Это значит, что они передаются как часть аргумента в правильной форме, а не удаляются или интерпретируются bash.
  • Вне темы: другие модификаторы выполняют такие действия, как изменение регистра, расширение в синтаксис или попытка защитить строки от атак внедрения.

Ответ или решение

Проблема, с которой вы столкнулись при использовании rsync с аргументами фильтра, переданными в виде массива в bash, связана с некорректной обработкой кавычек внутри элементов массива. Давайте разберем это пошагово и представим рекомендации по решению проблемы.

Проблема

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

  1. Избыточные кавычки: Вы добавляли лишние экранированные кавычки, которые интерпретировались как часть строки, вместо того чтобы влиять на способ интерпретации содержимого.

  2. Расширение массива: Использование неправильного метода расширения массива может приводить к тому, что элементы не интерпретируются как отдельные аргументы.

Решение

Для решения этой проблемы следуйте следующим шагам:

  1. Удалите лишние кавычки: Убедитесь, что используете кавычки только там, где это необходимо для группы аргументов, но не в самих элементах массива.

  2. Правильное расширение массива: Используйте "${array[@]}" для корректного расширения элементов массива, чтобы они интерпретировались как отдельные аргументы.

  3. Использование модификатора @E: Этот модификатор позволяет bash экранировать специальные символы, предотвращая их необычное поведение при передаче в rsync.

Пример исправленного кода

options=(
  -av --prune-empty-dirs 
  -f "- *.flac" 
  -f "- *.WMA" 
  -f "- *.wma" 
  -f "- *.ogg" 
  -f "- *.mp4" 
  -f "- *.m4a" 
  -f "- *.webm" 
  -f "- *.wav" 
  -f "- *.ape" 
  -f "- *.zip" 
  -f "- *.rar"
)
dir="/media/test/Ahmad Jamal Trio/Live at the Pershing"
target_dir="/home/test/mp3/Ahmad Jamal Trio/Live at the Pershing"
rsync "${options[@]}" "$dir/" "$target_dir"

Заключение

При работе с массивами в bash важно помнить о специфике интерпретации кавычек и расширения массивов. Обеспечение корректного использования кавычек и методов расширения предотвращает ошибки синтаксиса и использования. Обратите внимание на оптимальное использование двойных кавычек и модификаторов, таких как @E, для избежания непредсказуемого поведения. Это гарантирует, что команды выполняются точно так, как вы ожидаете, что особенно важно в командной строке и при работе с утилитами, такими как rsync.

SEO Оптимизация

Использование правильных терминов и нюансов bash программирования помогает не только устранить ошибки, но и повысить узнаваемость вашего контента среди других IT специалистов, ищущих решение подобных проблем. Подключение описательных названий и тегов к проблеме может помочь вашей статье быть видимой и полезной в различных контекстах.

Таким образом, ваше внимание к деталям в решении проблемы с rsync через bash демонстрирует высокую квалификацию и практическое понимание сложных технических задач.

Оцените материал
Добавить комментарий

Капча загружается...