Будуйте команду динамічно


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

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


Я вважаю, що параметр --exclude може прийняти лише один рядок після нього. Ти можеш мати кілька заявок --exclude. Можливо, спробуйте "--exclude = / tmp / hello --exclude = привіт" На жаль. Не звертай уваги. Я неправильно зрозумів.
Lewis M

@LewisM Я думаю, що ОП хочуть виключити каталог "/ tmp / hello hello" (так, з пробілом.
Archemar

@ShellCode, що з цитування всіх виключити, напр. "--Exclude = / tmp / hello hello"
Архемар

Так. Тому я поставив заяву Oops пізніше. :)
Lewis M

Як щодо виставлення evalперед стратою?
jimmij

Відповіді:


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.


Дуже дякую за вашу допомогу, але мені не дуже подобається eval, він досить небезпечний ... Більше того, цей код досить важко зрозуміти, чи не є у вас щось простіше? : / Сценарій буде розповсюджений, тому я повинен тримати його максимально просто ...
ShellCode

Це не небезпечно. Запустіть його set -x. Що саме ти не розумієш?
mosvy

Також прочитайте оригінальну відповідь про stackoverflow. Він включає демонстрацію.
mosvy

Хоча це працює досить добре ... Чекаю, чи хтось має більш чітку відповідь, інакше я прийму вашу. Можливо, у цьому коді немає нічого поганого, але щоразу, коли я бачу eval, я боюся, що код може призвести до введення команди, тому я намагаюся цього уникати
ShellCode

Я оновив відповідь виправленням для індексів> 9. Ви можете замінити eval на відлуння, щоб побачити, що насправді отримує (eval не бачить назви файлів)
mosvy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.