Bangun perintah secara dinamis

9

Saya sedang mengerjakan skrip dan saya perlu membangun tarperintah secara dinamis.

Berikut adalah dua contoh untuk menggambarkan apa yang saya coba lakukan:

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

Saya ingin dapat menggunakan _tarsebagai perintah, saya bisa membuatnya bekerja dengan jalur klasik, tetapi saya membutuhkannya untuk bekerja dengan spasi di nama folder. Dan setiap kali saya mendapatkan kesalahan yang terlihat seperti:

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

Hanya satu hal yang perlu Anda ketahui, saya perlu skrip saya untuk bekerja pada mesin yang sangat lama, artinya saya tidak dapat menggunakan fitur bash terakhir.

ShellCode
sumber
Saya percaya opsi --exclude hanya dapat menerima string tunggal setelahnya. Anda dapat memiliki beberapa pernyataan --exclude. Mungkin coba "--exclude = / tmp / hello --exclude = hello" Ups. Sudahlah. Saya salah paham.
Lewis M
@LewisM Saya pikir OP ingin mengecualikan direktori "/ tmp / halo halo" (ya, dengan spasi.
Archemar
@ShellCode bagaimana dengan mengutip semua mengecualikan, mis. "--Exclude = / tmp / hello hello"
Archemar
Ya. Itu sebabnya saya menaruh pernyataan Oops nanti. :)
Lewis M
Bagaimana dengan menempatkan evaldi depan eksekusi?
jimmij

Jawaban:

11

Jangan mencoba membuat string yang dapat dieksekusi. Alih-alih membangun argumen dalam array dan menggunakannya saat memanggil tar(Anda sudah menggunakan array dengan benar untuk 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"

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

Perhatikan mengutip dari $@dalam shkode dan kedua ${exclude[@]}dan ${exclude_opts[@]}di bashkode. Ini memastikan bahwa daftar diperluas ke elemen-elemen yang dikutip secara individual.

Terkait:

Kusalananda
sumber
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[@]}"

Memperluas jawabannya di sini . Ini tidak bergantung pada bashisme apa pun, ini juga akan bekerja dengan baik pada debian /bin/sh, dan dengan busybox.

mosvy
sumber
Terima kasih banyak atas bantuan Anda, tapi saya tidak terlalu suka eval, itu cukup berbahaya ... Selain itu, kode ini cukup sulit untuk dipahami, bukankah Anda memiliki sesuatu yang lebih mudah? : / Script akan didistribusikan jadi saya harus membuatnya sesederhana mungkin ...
ShellCode
Itu tidak berbahaya. Jalankan dengan set -x. Apa sebenarnya yang tidak kamu mengerti?
Mosvy
Juga, baca jawaban asli di stackoverflow. Ini termasuk demo.
Mosvy
Ini bekerja dengan sangat baik ... Menunggu untuk melihat apakah ada yang punya jawaban yang lebih bersih, kalau tidak saya akan menerima Anda. Mungkin tidak ada yang salah dengan kode itu, tetapi setiap kali saya melihat eval, saya khawatir kode itu dapat mengarah ke perintah injeksi, itu sebabnya saya mencoba menghindarinya
ShellCode
Saya telah memperbarui jawabannya dengan perbaikan untuk indeks> 9. Anda dapat mengganti eval dengan gema untuk melihat apa yang sebenarnya
didapat