Apakah mungkin untuk merujuk ke indeks $@
? Saya tidak dapat menemukan referensi untuk digunakan seperti di bagian mana saja di wiki GrayCat , dan Advanced Scripting Guide dan yang lainnya memberikan ini pada variabel yang berbeda sebelum mengubahnya.
$ echo ${@[0]}
-bash: ${@[0]}: bad substitution
Tujuannya KERING : Argumen pertama digunakan untuk satu hal, dan sisanya untuk sesuatu yang lain, dan saya ingin menghindari duplikasi kode untuk menormalkan, $@
array, atau untuk membuat fungsi terpisah untuk ini (walaupun saat ini titik itu mungkin jalan keluar termudah).
Klarifikasi: Objeknya adalah untuk memodifikasi nilai-nilai dari panjang variabel $@
untuk membuat kode lebih mudah untuk di-debug. Versi saat ini agak terlalu hacky untuk seleraku, meskipun itu berfungsi bahkan untuk jalur aneh seperti
$'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'
Pembaruan : Sepertinya ini tidak mungkin. Kode sekarang menggunakan duplikasi kode dan data, tetapi setidaknya berfungsi:
path_common()
{
# Get the deepest common path.
local common_path="$(echo -n "${1:-}x" | tr -s '/')"
common_path="${common_path%x}"
shift # $1 is obviously part of $1
local path
while [ -n "${1+defined}" ]
do
path="$(echo -n "${1}x" | tr -s '/')"
path="${path%x}"
if [[ "${path%/}/" = "${common_path%/}/"* ]]
then
shift
else
new_common_path="${common_path%/*}"
[ "$new_common_path" = "$common_path" ] && return 1 # Dead end
common_path="$new_common_path"
fi
done
printf %s "$common_path"
}
Bounty pergi ke siapa saja yang dapat menyingkirkan duplikasi kode untuk memangkas duplikasi garis miring atau duplikasi data untuk disimpan $1
dan parameter lainnya, atau keduanya, sambil menjaga kode ukuran yang masuk akal dan berhasil semua unit test:
test "$(path_common /a/b/c/d /a/b/e/f; echo x)" = /a/bx
test "$(path_common /long/names/foo /long/names/bar; echo x)" = /long/namesx
test "$(path_common / /a/b/c; echo x)" = /x
test "$(path_common a/b/c/d a/b/e/f ; echo x)" = a/bx
test "$(path_common ./a/b/c/d ./a/b/e/f; echo x)" = ./a/bx
test "$(path_common $'\n/\n/\n' $'\n/\n'; echo x)" = $'\n/\n'x
test "$(path_common --/-- --; echo x)" = '--x'
test "$(path_common '' ''; echo x)" = x
test "$(path_common /foo/bar ''; echo x)" = x
test "$(path_common /foo /fo; echo x)" = x
test "$(path_common $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n' $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'; echo x)" = $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'x
test "$(path_common /foo/bar //foo//bar//baz; echo x)" = /foo/barx
test "$(path_common foo foo; echo x)" = foox
test "$(path_common /fo /foo; echo x)" = x
Jawaban:
POSIX
Untuk menormalkan garis miring pada semua parameter, saya akan menggunakan trik argumen rotating: shift
$1
off, transform, dan letakkan hasilnya di akhir daftar parameter. Jika Anda melakukannya sebanyak waktu karena ada parameter, Anda telah mengubah semua parameter, dan Anda mendapatkannya kembali secara berurutan.Untuk bagian kedua dari kode, saya mengubah logika Anda menjadi kurang membingungkan: loop luar iterates atas parameter, dan loop dalam iterate di atas komponen path.
for x; do … done
iterates atas parameter posisi, itu adalah ungkapan yang nyaman. Saya menggunakan cara yang sesuai dengan POSIX untuk mencocokkan string dengan sebuah pola:case
konstruk.Diuji dengan tanda hubung 0.5.5.1, pdksh 5.2.14, bash 3.2.39, bash 4.1.5, ksh 93s +, zsh 4.3.10.
Catatan: sepertinya ada bug di bash 4.1.5 (bukan di 3.2): jika pola case-nya
"${common_path%/}"/*
, salah satu tes gagal.bash, ksh
Jika Anda menggunakan bash (atau ksh), Anda dapat menggunakan array - Saya tidak mengerti mengapa Anda tampaknya membatasi diri Anda ke parameter posisi. Berikut adalah versi yang menggunakan array. Saya harus mengakui itu tidak terlalu jelas dari versi POSIX, tetapi ia menghindari pengocokan awal n ^ 2.
Untuk bagian slash normalisasi, saya menggunakan ksh93 membangun
${foo//PATTERN/REPLACEMENT}
konstruk mengganti semua kejadian dariPATTERN
dalam$foo
olehREPLACEMENT
. Polanya adalah+(\/)
mencocokkan satu atau lebih garis miring; di bawah bash,shopt -s extglob
harus berlaku (setara, mulai bash denganbash -O extglob
). Konstrukset ${!a[@]}
menetapkan parameter posisi ke daftar subkrip arraya
. Ini memberikan cara mudah untuk beralih pada elemen-elemen array.Untuk bagian kedua, saya logika loop yang sama dengan versi POSIX. Kali ini, saya dapat menggunakan
[[ … ]]
karena semua shell yang ditargetkan di sini mendukungnya.Diuji dengan bash 3.2.39, bash 4.1.5, ksh 93s +.
zsh
Sayangnya, zsh tidak memiliki
${!array[@]}
fitur untuk menjalankan versi ksh93 apa adanya. Untungnya, zsh memiliki dua fitur yang membuat bagian pertama mudah. Anda bisa mengindeks parameter posisi seolah-olah mereka adalah@
array, jadi tidak perlu menggunakan array perantara. Dan zsh memiliki susunan iterasi susunan :"${(@)array//PATTERN/REPLACEMENT}"
melakukan penggantian pola pada setiap elemen susunan secara bergantian dan mengevaluasi susunan hasil (membingungkan, Anda memang membutuhkan tanda kutip ganda walaupun hasilnya beberapa kata; ini adalah generalisasi dari"$@"
). Bagian kedua pada dasarnya tidak berubah.Uji kasus
Solusi saya minimal diuji dan dikomentari. Saya telah mengubah sintaks kasus uji Anda untuk menguraikan di bawah shell yang tidak memiliki
$'…'
dan melaporkan kegagalan dengan cara yang lebih nyaman.sumber
Mengapa Anda tidak menggunakan $ 1, $ 2 .. $ 9, $ {10}, $ {11} .. dan seterusnya? Ini bahkan lebih KERING- daripada apa yang Anda coba lakukan :)
Lebih lanjut tentang hubungan antara $ number dan $ @:
$ @ dapat dianggap sebagai singkatan untuk "semua elemen dari array yang berisi semua argumen"
Jadi, $ @ adalah semacam singkatan dari $ {args [@]} (args di sini adalah array 'virtual' yang berisi semua argumen - bukan variabel nyata, ingatlah)
$ 1 adalah $ {args [1]}, $ 2 adalah $ {args [2]}, dan seterusnya.
Saat Anda menekan [9], gunakan tanda kurung: $ {10} adalah $ {args [10]}, $ {11} adalah $ {args [11]}, dan seterusnya.
Secara tidak langsung menggunakan argumen baris perintah
Contoh:
sumber
${args[$i]}
.Saya pikir apa yang Anda inginkan
shift
sumber
Saya tidak tahu mengapa Anda tidak hanya menggunakan $ 1 $ 2, dll. Tapi .. Ini mungkin sesuai dengan kebutuhan Anda.
keluaran
set
karya apa pun yang mengikutinya, untuk membuat $ 1, $ 2 .. dll. Ini tentu saja akan mengesampingkan nilai-nilai asli, jadi hanya perlu diketahui itu.sumber
eval
dianggap oleh sebagian orang sebagaievil
... (mungkin karena ejaannya :) ... Jikaeval
"buruk", apakah $ {! Var} sama dengan "buruk"? ... Bagi saya itu hanya bagian dari bahasa, dan bagian yang berguna, pada saat itu .. tapi saya lebih suka $ {! Var} ...Catatan saya mendukung spasi dalam nama file.
Saya menambahkan kasus uji untuk nama file dengan spasi dan memperbaiki 2 tes yang tidak ada yang memimpin /
sumber