Построить команду динамически

9

Я работаю над сценарием, и мне нужно построить tarкоманду динамически.

Вот два примера, чтобы проиллюстрировать, что я пытаюсь сделать:

#!/bin/bash

TAR_ME="/tmp"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
_tar="tar "`printf -- '--exclude="%s" ' "${EXCLUDE[@]}"`" -zcf tmp.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

echo -e "\n\nNEXT:\n\n"

EXCLUDE=("--exclude=/tmp/hello\ hello" "--exclude=/tmp/systemd*" "--exclude=/tmp/Temp*")
_tar="tar "`printf -- '%s ' "${EXCLUDE[@]}"`" -zcf test.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

Я хочу иметь возможность использовать _tarв качестве команды, я смог заставить ее работать с классическим путем, но мне нужно, чтобы она работала с пробелами в имени папки. И каждый раз, когда я получаю ошибки, которые выглядят так:

COMMAND: tar --exclude="/tmp/hello hello" --exclude="/tmp/systemd*" --exclude="/tmp/Temp*"  -zcf tmp.tar.gz /tmp
tar: hello": Cannot stat: No such file or directory

COMMAND: tar --exclude=/tmp/hello\ hello --exclude=/tmp/systemd* --exclude=/tmp/Temp*  -zcf test.tar.gz 
tar: hello: Cannot stat: No such file or directory

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

Shellcode
источник
Я считаю, что параметр --exclude может принимать только одну строку после него. Вы можете иметь несколько операторов --exclude. Может быть, попробуйте "--exclude = / tmp / hello --exclude = hello" Упс. Ничего. Я неправильно понял.
Льюис М
@LewisM Я думаю, что OP хочет исключить каталог "/ tmp / hello hello" (да, с пробелом.
Archemar
@ShellCode как насчет цитирования всех исключений, например, "--exclude = / tmp / hello hello"
Archemar
Да. Вот почему я поместил утверждение Oops позже. :)
Льюис М
Как насчет того, чтобы поставить evalперед казнью?
Джимми

Ответы:

11

Не пытайтесь создать исполняемую строку. Вместо этого соберите аргументы в массиве и используйте его при вызове tar(для этого вы уже правильно используете массив EXCLUDE):

#!/bin/bash

directory=/tmp

exclude=( "hello hello" "systemd*" "Temp*" )

# Now build the list of "--exclude" options from the exclude array:
for elem in "${exclude[@]}"; do
    exclude_opts+=( --exclude="$directory/$elem" )
done

# Run tar
tar -cz -f tmp.tar.gz "${exclude_opts[@]}" "$directory"

С /bin/sh:

#!/bin/sh

directory=/tmp

set -- "hello hello" "systemd*" "Temp*"

# Now build the list of "--exclude" options from the $@ array
# (overwriting the values in $@ while doing so)
for elem do
    set -- "$@" --exclude="$directory/$elem"
    shift
done

# Run tar
tar -cz -f tmp.tar.gz "$@" "$directory"

Обратите внимание на цитирование $@в shкоде и того и другого ${exclude[@]}и ${exclude_opts[@]}в bashкоде. Это гарантирует, что списки будут расширены до отдельных элементов в кавычках.

Связанные с:

Кусалананда
источник
2
mix(){
        p=$1; shift; q=$1; shift; c=
        i=1; for a; do c="$c $q \"\${$i}\""; i=$((i+1)); done
        eval "${p%\%*}$c${p#*\%}"
}
mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
mix 'tar % -zcf tmp.tar.gz' --exclude "${EXCLUDE[@]}"

Расширяя ответ здесь . Это не зависит от каких-либо ошибок, также будет хорошо работать с Debian /bin/shи с busybox.

mosvy
источник
Большое спасибо за вашу помощь, но мне не очень нравится eval, он довольно опасен ... Более того, этот код довольно сложен для понимания, разве у вас нет ничего проще? : / Сценарий будет распространяться, поэтому я должен держать его как можно более простым ...
ShellCode
Это не опасно. Запустите это с set -x. Что именно вы не понимаете?
Мосви
Также прочитайте оригинальный ответ на stackoverflow. Это включает в себя демо.
Мосви
Это работает довольно хорошо, хотя ... Ожидание, чтобы видеть, есть ли у кого-нибудь более чистый ответ, иначе я приму Ваш. Возможно, в этом коде нет ничего плохого, но каждый раз, когда я вижу eval, я боюсь, что этот код может привести к внедрению команд, поэтому я стараюсь избегать его
ShellCode
Я обновил ответ исправлением для индексов> 9. Вы можете заменить eval на эхо, чтобы увидеть, что на самом деле происходит (eval не видит имена файлов)
mosvy