Shell Script: membuat variabel dengan opsi di dalamnya

11

Saya punya perintah rsync dengan parameter berikut:

rsync -avz --{partial,stats,delete,exclude=".*"}

Saya ingin meletakkan parameter di dalam variabel untuk menggunakannya kembali setelah dalam skrip. Sesuatu seperti ini:

#!/bin/bash
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}
$VAR /dir1 /dir2

Saya sudah mencoba dengan tanda kutip, tanda kutip tunggal, tanda kurung, tanpa hasil.

Kellyson
sumber
Pertanyaan serupa pada SO: stackoverflow.com/questions/13365553/…
Barmar
Telah melalui rute ini sebelumnya: Pastikan string perintah hasil akhir Anda tidak memiliki string kosong di dalamnya. Jika ya, rsync dapat menggunakannya sebagai parameter dan karena tidak terlihat, cukup sulit untuk di-debug. Saya memiliki parameter pertama yang kosong dan rsync menafsirkannya sebagai termasuk direktori saat ini di sumber yang akan disalin.
Joe

Jawaban:

12

Menempatkan perintah kompleks dalam variabel adalah pendekatan yang tidak pernah direkomendasikan. Lihat BashFAQ / 050 - Saya mencoba untuk menempatkan perintah dalam variabel, tetapi kasus kompleks selalu gagal!

Persyaratan Anda menjadi sangat sederhana, jika Anda hanya memutuskan untuk menggunakan fungsi alih-alih variabel dan meneruskan argumen ke sana.

Sesuatu seperti

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --{partial,stats,delete,exclude=".*"} "$@"
}

dan sekarang berikan argumen yang diperlukan sebagai

rsync_custom /dir1 /dir2

Definisi fungsinya cukup sederhana, pertama-tama kita periksa jumlah argumen input menggunakan variabel $#yang seharusnya tidak nol. Kami melemparkan pesan kesalahan yang mengatakan bahwa tidak ada argumen yang diberikan. Jika ada argumen yang valid, maka "$@"mewakili argumen aktual yang disediakan untuk fungsi tersebut.

Jika ini adalah fungsi yang akan Anda gunakan cukup sering yaitu di skrip / command-line juga, tambahkan ke file startup shell .bashrc, .bash_profilemisalnya.

Atau seperti yang disebutkan, mungkin perlu untuk memperluas ekspansi brace untuk memisahkan args agar lebih mudah dibaca

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --partial --stats --delete --exclude=".*" "$@"
}
Inian
sumber
5
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

Ini mencoba menjalankan perintah -avzdengan argumen --partial, --statsdll. Dan dengan VARset ke rsyncdalam lingkungan.

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

Formulir yang dikutip tidak berfungsi karena kurung kurawal tidak diperluas dalam tanda kutip, dan tidak ada di dalam assigments, dan juga tidak diperluas setelah variabel diperluas.

Jika Anda perlu menyimpan argumen baris perintah dalam variabel, gunakan array:

args=(rsync -avz --{partial,stats,delete,exclude=".*"})

Sekarang "${args[@]}"akan diperluas untuk rsync, -avz, --partial, dll sebagai kata-kata yang berbeda.

Array juga memungkinkan Anda untuk menambahkan opsi ke daftar, jika diperlukan secara kondisional, sehingga Anda dapat misalnya:

args=(this that)
if something ; then
    args+=(another_arg)
fi
"$cmd" "${args[@]}"
ilkkachu
sumber
1

Anda setidaknya bisa menyimpan sebagian opsi dalam variabel:

opts=$(echo --{ignore-case,word-regexp,count,exclude='"sys*.*"'})

Pengujian itu penting, karena menutupi bisa sulit:

echo $opts
--ignore-case --word-regexp --count --exclude="sys*"

grep $opts bytes *.log 

Karena ada beberapa alternatif, seperti menggunakan riwayat, menggunakan alias, menggunakan fungsi, tidak ada use-case yang jelas yang bisa saya pikirkan. Jarang ada opsi berbagi yang rumit antara berbagai program, jadi untuk solusi ad-hoc untuk shell interaktif, aliasing tampaknya merupakan cara yang lebih baik:

alias cgrep='grep --ignore-case --word-regexp --count --exclude="sys*"'
cgrep bytes *.log

Sampel anda

VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

tidak dapat bekerja, karena penugasan berakhir di kosong pertama. Anda harus menutupi yang kosong:

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

hal yang cukup berbahaya untuk pengujian, dengan opsi --delete itu, bukan? Karena opsi dapat berisi lagi "," dan tanda kutip tunggal, masking bisa menjadi sangat sulit segera. Saya akan mencari alias atau mengandalkan sejarah.

Alias ​​dapat disimpan dalam file ~ / .bashrc untuk digunakan terus menerus selama beberapa sesi. Fungsi dapat disimpan di bashrc juga, tetapi Anda hanya memerlukannya, jika Anda ingin menangani parameter, diteruskan ke fungsi yang akan dievaluasi di dalamnya.

Pengguna tidak diketahui
sumber