Zbuduj polecenie dynamicznie

9

Pracuję nad skryptem i muszę tardynamicznie budować polecenie.

Oto dwa przykłady ilustrujące to, co próbuję zrobić:

#!/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"

Chcę móc używać _tarjako polecenia, udało mi się sprawić, aby działał z klasyczną ścieżką, ale potrzebuję go do pracy ze spacjami w nazwie folderów. I za każdym razem mam błędy, które wyglądają jak:

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

Tylko jedna rzecz, którą musisz wiedzieć: potrzebuję mojego skryptu do pracy na bardzo starych maszynach, co oznacza, że ​​nie mogę korzystać z funkcji ostatniego basha.

ShellCode
źródło
Wierzę, że opcja --exclude może zaakceptować tylko jeden ciąg po nim. Możesz jednak mieć wiele instrukcji --exclude. Może spróbuj „--exclude = / tmp / hello --exclude = hello” Ups. Nieważne. Źle zrozumiałem.
Lewis M
@LewisM Myślę, że OP chce wykluczyć katalog „/ tmp / hello hello” (tak, ze spacją.
Archemar
@ShellCode co z cytowaniem wszystkich wykluczeń, np. „--Exclude = / tmp / hello hello”
Archemar
Tak. Dlatego umieściłem oświadczenie Oops później. :)
Lewis M
Co powiesz na postawienie evalprzed egzekucją?
jimmij

Odpowiedzi:

11

Nie próbuj tworzyć wykonywalnego ciągu. Zamiast tego buduj argumenty w tablicy i używaj tego podczas wywoływania tar(już używasz poprawnie tablicy 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"

Z /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"

Zwróć uwagę na cytowanie $@w shkodzie i zarówno w kodzie, jak ${exclude[@]}i ${exclude_opts[@]}w bashkodzie. Zapewnia to, że listy są rozwijane do indywidualnie cytowanych elementów.

Związane z:

Kusalananda
źródło
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[@]}"

Rozszerzając odpowiedź tutaj . To nie opiera się na żadnych baszizmach, będzie również działało dobrze z debianem /bin/shi busybox.

mosvy
źródło
Bardzo dziękuję za pomoc, ale tak naprawdę nie podoba mi się eval, jest dość niebezpieczny ... Co więcej, ten kod jest dość trudny do zrozumienia, czy nie masz czegoś łatwiejszego? : / Skrypt zostanie rozpowszechniony, więc muszę go maksymalnie
uprościć
To nie jest niebezpieczne. Uruchom to z set -x. Czego dokładnie nie rozumiesz?
mosvy
Przeczytaj także oryginalną odpowiedź na temat przepełnienia stosu. Zawiera demo.
mosvy
Działa całkiem dobrze ... Czekam, czy ktoś ma czystszą odpowiedź, w przeciwnym razie zaakceptuję twoją. Może nie ma nic złego w tym kodzie, ale za każdym razem, gdy widzę eval, obawiam się, że kod może doprowadzić do wstrzyknięcia komendy, dlatego staram się tego unikać
ShellCode
Zaktualizowałem odpowiedź poprawką dla indeksów> 9. Możesz zastąpić eval echem, aby zobaczyć, co się właściwie dostaje (eval nie widzi nazw plików)
mosvy