Mengapa spasi antara opsi dan parameter dihilangkan?

16

Sebagai contoh:

xargs -n 1

sama dengan

xargs -n1

Tetapi jika Anda melihat halaman manual, opsi terdaftar sebagai -n max-args, yang berarti ruang seharusnya dipertahankan. Tidak ada tentang bentuk disingkat -n max-args .

Ini juga terjadi dengan banyak utilitas Linux lainnya.

Apa ini namanya di Linux? Apakah semua utilitas mendukung formulir yang disingkat (tetapi tidak pernah mendokumentasikannya di halaman manual)?

J. Jo
sumber
1
12.1.2.a adalah sebagian dari sejarah; Saya bersumpah sudah ada pertanyaan yang bagus di sini tentang ini tetapi saya belum menemukannya.
2
@drewbenn pertanyaan lain yang Anda pikirkan mungkin adalah pertanyaan saya: unix.stackexchange.com/q/188046/41515

Jawaban:

12

Saat Anda menulis sedikit baris perintah parsing kode Anda, Anda menentukan opsi apa yang mengambil argumen dan mana yang tidak. Misalnya, dalam skrip shell yang menerima -hopsi (untuk bantuan misalnya) dan -aopsi yang harus mengambil argumen, Anda lakukan

opt_h=0     # default value
opt_a=""

while getopts 'a:h' opt; do
    case $opt in
        h)  opt_h=1 ;;
        a)  opt_a="$OPTARG" ;;
    esac
done

echo "h: $opt_h"
echo "a: $opt_a"

The a:hbit mengatakan "Saya mengharapkan untuk mengurai dua pilihan, -adan -h, dan -aharus mengambil argumen" (itu adalah :setelah ayang memberitahu parser yang -amengambil argumen).

Oleh karena itu, tidak pernah ada ambiguitas di mana opsi berakhir, di mana nilainya dimulai, dan di mana yang lain dimulai setelah itu.

Menjalankannya:

$ bash test.sh -h -a hello
h: 1
a: hello

$ bash test.sh -h -ahello
h: 1
a: hello

$ bash test.sh -hahello
h: 1
a: hello

Inilah sebabnya mengapa Anda sebagian besar waktu seharusnya tidak menulis parser baris perintah Anda sendiri untuk opsi parse.

Hanya ada satu kasus dalam contoh ini yang rumit. Penguraian biasanya berhenti pada opsi pertama, jadi ketika Anda memiliki item di baris perintah yang terlihat seperti opsi:

$ bash test.sh -a hello -world
test.sh: illegal option -- w
test.sh: illegal option -- o
test.sh: illegal option -- r
test.sh: illegal option -- l
test.sh: illegal option -- d
h: 0
a: hello

Berikut ini memecahkan itu:

$ bash test.sh -a hello -- -world
h: 0
a: hello

The --sinyal mengakhiri opsi baris perintah, dan -worldbit yang tersisa untuk program untuk melakukan apapun yang diinginkan dengan (itu di salah satu variabel posisi).

Omong-omong, bagaimana Anda menghapus file yang memiliki tanda hubung di awal nama file-nya rm.

EDIT :

Utilitas yang ditulis dalam panggilan C getopt()(dinyatakan dalam unistd.h) yang bekerja dengan cara yang hampir sama. Bahkan, untuk semua yang kita tahu, bashfungsi getoptstersebut dapat diimplementasikan menggunakan panggilan ke fungsi C library getopt(). Perl, Python dan bahasa lain memiliki parsing pustaka baris perintah yang sama, dan kemungkinan besar parsing mereka lakukan dengan cara yang sama.

Beberapa ini getoptdan getopt-seperti rutinitas perpustakaan juga menangani "lama" pilihan. Ini biasanya didahului dengan double-dash ( --), dan opsi panjang yang mengambil argumen sering melakukannya setelah tanda sama dengan, misalnya --block-size=SIZEopsi [beberapa implementasi] duutilitas (yang juga memungkinkan untuk -B SIZEmenentukan hal yang sama).

Alasan mengapa manual sering ditulis untuk menunjukkan ruang di antara opsi pendek dan argumen mereka mungkin untuk dibaca.

EDIT : Alat yang benar - benar tua, seperti dddan tarutilitas, memiliki opsi tanpa tanda hubung di depannya. Ini murni karena alasan historis dan untuk menjaga kompatibilitas dengan perangkat lunak yang bergantung pada mereka untuk bekerja dengan cara seperti itu. The tarutilitas telah memperoleh kemampuan untuk mengambil pilihan dengan strip di kali yang lebih baru. Manual BSD untuk tarpanggilan opsi gaya lama untuk "bundled flags".

Kusalananda
sumber
Fitur ini mungkin tampak mudah diimplementasikan dalam bash scripting. Tapi saya pikir sebagian besar utilitas ditulis dalam C (kemudian dikompilasi ke binari) bukan bash. Mengapa utilitas ini mengimplementasikan fitur ini?
J.Joe
@ J. Joe Karena mereka memanggil getopt()(dinyatakan dalam unistd.h), yang melakukan hal yang sama.
Kusalananda
2
Yap, kamu benar. Referensi . Ini juga memecahkan misteri lain bahwa opsi dapat dikombinasikan -a -b=== -ab
J.Joe
1
Argumen opsional untuk flag akan menciptakan ambiguitas, sehingga tidak dapat digabungkan (jika -amemiliki argumen opsional, -abtidak sama dengan -a -b). GNU getopt tidak menghentikan pemrosesan flag saat bertemu dengan non-flag: sebagai gantinya (secara default), ia malah merombak flag ke bagian depan argv.
ilkkachu
@ilkkachu Terima kasih atas klarifikasi itu. Saya dapat memperbarui jawaban saya nanti.
Kusalananda
4

xargsadalah salah satu utilitas POSIX. Seperti dikomentari oleh @drewbenn, POSIX mendokumentasikan perilaku parsing opsi untuk sebagian besar utilitasnya agar sesuai getopt, dengan beberapa kelonggaran untuk implementasi lainnya, mengatakan dalam 12.1 Utilitas Sintaks Argumen Sintaks :

Bagian ini menguraikan sintaks argumen dari utilitas standar dan memperkenalkan terminologi yang digunakan di seluruh POSIX.1-2008 untuk menjelaskan argumen yang diproses oleh utilitas.

Dalam POSIX.1-2008, notasi khusus digunakan untuk menggambarkan sintaksis argumen utilitas. Kecuali disebutkan sebaliknya , semua deskripsi utilitas menggunakan notasi ini, yang diilustrasikan oleh contoh ini (lihat Perintah Sederhana XCU ):

dan menyimpulkan dengan

Disarankan bahwa semua utilitas dan aplikasi di masa depan menggunakan pedoman ini untuk meningkatkan portabilitas pengguna. Fakta bahwa beberapa utilitas historis tidak dapat diubah (untuk menghindari kerusakan aplikasi yang ada) tidak boleh menghalangi tujuan masa depan ini.

Di dalam POSIX (ingat bahwa itu hanya mencakup utilitas yang paling umum digunakan), ada pengecualian yang melewati operan yang akan menjadi opsi di utilitas lain sebagai parameter posisional , atau parameter dengan sintaks khusus :

POSIX memungkinkan untuk opsi-nilai opsional :

Opsi-argumen ditampilkan terpisah dari opsi mereka dengan <blank>karakter, kecuali ketika argumen-opsi terlampir dalam '['dan ']'notasi untuk menunjukkan bahwa itu opsional.

Begitu saja, saya tidak ingat utilitas POSIX mana yang menggunakan fitur ini. Ncurses ticdan infocmputilitas menggunakan fitur untuk level opsi -v(verbose / debug).

Poin spesifik yang Anda tanyakan terperinci dalam sisa paragraf itu, berlangsung beberapa baris.

Sebelum POSIX, beberapa implementasi dari psopsi yang diterima tanpa tanda hubung terkemuka. Deskripsi POSIX tidak menyebutkan bahwa dalam deskripsi utilitas atau dalam alasan sintaksis:

Selain POSIX, ada implementasi opsi-panjang (seperti GNU getopt_long , atau X Toolkit ), menggunakan berbagai cara untuk memisahkan atau menggabungkan nilai opsi ke opsi. Misalnya, tanda baca dapat digunakan:

--option=value
--option value

Bergantung pada implementasinya, dasbor ganda dapat / mungkin tidak digunakan untuk membedakan opsi panjang dari pendek (getopt): lynx dan X Toolkit menggunakan dasbor tunggal; GNU getopt_longmenggunakan tanda hubung ganda, misalnya. Juga, a +dapat digunakan untuk menunjukkan bahwa opsi dinegasikan.

Deskripsi POSIX tampaknya tidak menyebutkan semua ini, tetapi Anda pasti akan menemui mereka.

Thomas Dickey
sumber
Apakah -option=valueseharusnya --option=value(format lama-pilihan, dua strip di awal bukan satu)?
J.Joe
Beberapa utilitas lama menggunakan opsi panjang dasbor tunggal (-option) tetapi sebagian besar tidak digunakan untuk skrip dan program baru. Gunakan tanda hubung tunggal untuk opsi pendek seperti yang ditangani oleh getopt. Hampir semua skrip dan program baru menggunakan opsi panjang dasbor ganda. Banyak juga yang mendukung opsi setara pendek dasbor tunggal untuk yang paling umum digunakan. Opsi panjang membuat kode skrip jauh lebih banyak mendokumentasikan diri sendiri, membutuhkan lebih sedikit komentar.
DocSalvager