Komut satırı argümanlarını tasarlamak için iyi alışkanlıklar nelerdir?


190

Uygulamayı geliştirirken merak etmeye başladım - Komut satırı argümanlarını nasıl tasarlamalıyım?

Program bir çok böyle formülü kullanan -argument valueveya /argument value. Aklıma gelen çözüm oldu argument:value. Bunun iyi olduğunu düşündüm çünkü beyaz boşluk olmadan değerlerin ve argümanların karışmasına imkan yok. Ayrıca bir dizgiyi soldaki :karakterden ilk önce ikiye bölmek kolaydır .

Benim sorularım:

  1. Popüler -argument valueformül daha iyi argument:value(daha okunur, yazması kolay, hatasız, uzman geliştiriciler tarafından anlaşılması daha kolay) mı?
  2. Komut satırı argümanlarını tasarlarken izlemem gereken yaygın olarak bilinen bazı kurallar var mı (çalışıyorsa sorun değil).

Daha fazla bilgi istemiştim. Ancak cevapları etkilememeleri gerektiğini düşünüyorum. Soru genel olarak iyi bir alışkanlık ile ilgilidir. Her türlü uygulama için hepsinin aynı olduğunu düşünüyorum.

Halka açık yerlerde kullanılacak bir uygulama üzerinde çalışıyoruz (dokunmatik totemler, tablolar). Uygulamalar Qt Quick 5 (C ++, QML, JS) kullanılarak yazılmıştır. Cihazlarda Windows 8.1 / 10 yüklü olacaktır. Cihazları yönetmek için ön uç arayüz sağlayacağız. Ancak, bazı gelişmiş yöneticiler uygulamayı kendi başlarına yapılandırmak isteyebilir. Bu iş açısından çok önemli değil ama Kilian Foth'un söylediklerine katılıyorum çünkü başvurumun bir kullanıcı için acı verici olmasını istemiyorum. İnternette istediğim şeyi bulamıyorum burada sordum.


Daha gelişmiş Stack Exchange kullanıcıları için: Bu sorunun genel olmasını istedim. Belki topluluk wiki'sine uygun olabilir (mevcut sorunun cevaplarla dönüştürülüp dönüştürülmeyeceğini bilmiyorum). Bu sorunun işletim sistemi ve programlama dilinden bağımsız olmasını istediğim için burada görünen cevaplar diğer geliştiriciler için değerli bir ders olabilir.


14
Popüler komut satırı araçlarına bakın. Örneğin, tek kısa çizgi, birleştirme seçeneklerine izin vermek için sıklıkla kullanılır. örneğin şunları yazabilirsiniz ls -ltrseçeneğin birleştirilmesidir -l, -tve -r. GNU tarzı programlar da tipik olarak, --reverseyerine bir çift tire ile kelime tabanlı seçeneklere izin verir -r. -hYardım etmek, --seçeneklerin sonunu işaret etmek, -stdin'den okumaya izin vermek için bir dosya adı olarak belirtmek vb. Gibi diğer popüler sözleşmeler var .
Brandin

72
Hiçbiri ortak -argument valuedeğil -argument:value. Ortak olan -a value, -avalueve --argument=value.
reinierpost

39
Kitaplığı (genellikle benzer bir şey denir getopt(s)) bulabileceğiniz popüler bir komut satırı kullanın .
reinierpost

5
@ k3b Qt ile çalışıyoruz. As Kevin Cline söyledi onun comment biz zaten mevcut kütüphaneyi kullanabilirsiniz. Sanırım çok platformlu ve iyi düşünülmüş. QCommandLineParser
Filip Hazubski

11
Son bulanıklığınızla ilgili sorun, argüman ayrıştırmanın platformdan bağımsız bir sorun olmamasıdır.
pydsigner

Yanıtlar:


237

POSIX sistemlerinde (örneğin Linux, MacOSX), en azından bir kabuk terminalinde başlatılan programlar için (örneğin çoğu), GNU kodlama kurallarını (ortak argüman adlarını da listeleyen) kullanmanızı ve POSIX yardımcı programları kurallarına bakmanızı öneririm. , özel yazılım için bile:

  • her zaman idare --versionve--help (hatta /bin/trueonları kabul eder !!). Ben yazılımın yazarları anlamak değil küfür --help(çünkü onlardan nefret, prog --help bir ilk komut yeni bir program üzerinde çalışıyorum)! Genellikle --helpkısaltılabilir-h

  • Var --help(en yaygın olanları ve bu durumda listede ... onlardan daha çok yoksa bütün seçenekler ileti listesini açıkça bazı atıfta manve seçeneklerin varsayılan değerler sayfası veya bazı URL) ve belki önemli (ve programa özgü ) Ortam Değişkenleri. Bu seçenek listelerini seçenek argümanı hatası üzerinde göster.

  • kabul -akısa argüman (tek harf) ve bazı eşdeğer --long-argument, bu yüzden -a2 --long-argument=2, --long-argument 2; Tabii ki (nadiren kullanılan seçenekler için) bir --only-long-argumentisim olabilir; Ekstra seçenekler olmadan modal argümanlar -cfgenellikle -c -f, vb. gibi ele alınır , bu yüzden -argument:valueteklifin garip ve bunu yapmanı tavsiye etmiyorum.

  • GLIBC getopt_long veya daha iyisini kullanın (örneğin argp_parse , OCaml's Argmodülünde , ...)

  • Sık kullandığınız -(bunu yapamazsanız, idare standart giriş veya çıkış için /dev/stdinve /dev/stdouthatta birkaç işletim sistemlerinde onları olmamasından)

  • seçenek programlarının çoğunu yeniden kullanarak benzer programların davranışlarını taklit etmek ; özellikle -nkuru çalışma (à la make), -hyardım, -vayrıntılandırma vb. için ...

  • --seçenekler ve dosyalar veya diğer argümanlar arasında ayırıcı olarak kullanın

  • Eğer programınız stdin'denisatty daha sınamak için kullanıyorsa (ve bu durumda "etkileşimli" davranıyorsanız), etkileşimli olmayan modu zorlamak için bir seçenek sunun, eğer programınız bir GUI arayüzüne sahipse (ve X11 masaüstünde test eder ) toplu iş veya komut satırında kullanılmalıdır.getenv("DISPLAY")

  • Bazı programlar (örn gcc), böylece dolaylı argüman listelerini kabul @somefile.txtokunan programın argümanları anlam edilir somefile.txt; Programınız çok fazla sayıda argümanı kabul ederse bu yararlı olabilir (çekirdeğinizden fazla ARG_MAX)

BTW, programınız ve normal mermileriniz için otomatik tamamlama olanakları bile ekleyebilirsiniz ( bashya da gibi zsh)

Bazı eski Unix komutları (örneğin ddveya hatta sed) tarihsel uyumluluk için garip komut argümanlarına sahiptir. Kötü alışkanlıklarına uymamanı tavsiye ederim (daha iyi bir değişken yapmıyorsanız).

Yazılımınız bir dizi ilgili komut satırı programındaysa, kabul eden ve çok sayıda özelliği olan ve kesinlikle bir geliştirme aracı olarak kullandığınız git'ten ilham alın.git helpgit --helpgitsubcommandgitsubcommand--help

Nadir durumlarda da kullanabilir argv[0](programa üzerine sembolik kullanarak), örneğin basholarak çağrılan rbashfarklı bir davranış (vardır kısıtlı kabuk). Ama genelde bunu yapmayı önermiyorum; Programınızın shebang'ı kullanarak, yani execve (2)#! tarafından ilk satırda yorumlanan bir komut dosyası tercümanı olarak kullanılıp kullanılamayacağı mantıklı olabilir . Böyle hileler yaparsanız, iletiler dahil olmak üzere bunları belgelendiğinizden emin olun .--help

POSIX unutmayın kabuk edilir globbing (argümanlar önce ! Programınızı çalıştıran), yani (gibi karakterler gerektiren önlemek *veya $veya ~kabuk kaçan olması gerekir seçeneklerinde).

Bazı durumlarda, yazılımınıza GNU guile veya Lua gibi bir tercüman ekleyebilir ( programlama dillerinde uzman değilseniz kendi Turing-komple kodlama dilinizi icat etmekten kaçının ). Bunun, yazılımınızın tasarımı üzerinde derin sonuçları vardır (bu nedenle erken düşünülmelidir!). Daha sonra bu tercümana bir komut dosyasını veya bir ifadeyi kolayca iletebilmelisiniz. Bu ilginç yaklaşımı benimserseniz, yazılımınızı ve yorumlanmış ilkellerini dikkatlice tasarlayın; işiniz için büyük betikleri kodlayan garip bir kullanıcı olabilir.

Diğer durumlarda, ileri düzeydeki kullanıcıların eklentilerini yazılımınıza yüklemelerine izin vermek isteyebilirsiniz ( à la & dinamik yükleme tekniklerini kullanarak ). Yine, bu çok önemli bir tasarım kararıdır (eklenti arayüzünü dikkatli bir şekilde tanımlayın ve belgeleyin) ve program seçeneklerini bu eklentilere geçirmek için bir kural tanımlamanız gerekir.dlopendlsym

Yazılımınız karmaşık bir şeyse, bazı yapılandırma dosyalarını (program argümanlarının eklenmesine veya değiştirilmesine ek olarak) kabul etmesini sağlayın ve muhtemelen tüm kodları çalıştırmadan bu yapılandırma dosyalarını test etmek (veya yalnızca ayrıştırmak) için bir yol vardır. Örneğin, bir posta aktarım aracısı (Exim veya Postfix gibi) oldukça karmaşıktır ve "yarı kuru" olarak çalışabilmesi yararlıdır (örneğin, belirli bir e-posta adresini gerçekten bir e-posta göndermeden nasıl işlediğini gözlemleyerek).


Bunun /optionbir Windows veya VMS olayı olduğuna dikkat edin . POSIX sistemlerinde delilik olurdu (çünkü dosya hiyerarşisi /bir dizin ayırıcı olarak kullanır ve kabuk globbing yapar). Tüm cevabım çoğunlukla Linux (ve POSIX) içindir.


Not Mümkünse, programınızı ücretsiz bir yazılım haline getirin , bazı kullanıcılardan ve geliştiricilerden iyileştirmeler elde edersiniz (ve yeni bir program seçeneği eklemek genellikle mevcut bir özgür yazılıma eklenmesi en kolay şeylerden biridir). Ayrıca, sorunuzun amacı hedef kitleye çok bağlıdır : büyükler için bir oyun veya büyükanne için bir tarayıcı muhtemelen bir derleyici ile aynı tür ve miktarda seçeneklere veya veri merkezi sysadmins için bir ağ denetçisine veya mikroişlemci için bir CAD yazılımına ihtiyaç duymaz. mimarlar veya köprü tasarımcıları için. Programlama ve senaryoya aşina bir mühendis, büyükannenizden çok daha fazla ayarlanabilir seçeneğe sahip olmaktan çok hoşlanıyor ve muhtemelen başvurunuzu X11 olmadan (belki de bir crontabişte) yürütmek isteyebilir .


18
Kabul, ancak git daha iyi bir örnek. Hatta tavsiye olmaz seyir halinde cvs2016 yılında
Basile Starynkevitch

8
+ geçersiz seçenek durumunda sadece yardım göster. Örneğin SOOOO, işe yaramaz bir hata mesajı almak için can sıkıcı bir durum dd -h.
domen

8
GNU programları --helpbir kural olarak desteklenir ancak çoğu zaman -hhangisinin can sıkıcı olduğunu tanımıyor . Genellikle bir program için bir seçenek unuttuğumda -h yazarım, komutu daha uzun seçenekle yeniden yazmak zorunda kalmak can sıkıcıdır --help. Sonuçta, ben yazdım -h çünkü bir şey unuttum. Kullanıcının, yardım ekranını göstermek için hangi progamların '--help' gerektiğini ve hangi programların '-h' gerektiğini hatırlaması bekleniyor? Sadece -h ve --help seçeneklerinin ikisini de ekleyin.
Brandin

30
Bu cevabın ilk kısmı iyi, ancak etrafınızdaki bir yerde teğet şeyler oluyor. Örneğin, yapılandırma dosyaları, eklentiler ve dlopen, yazılım lisansları ve Web tarayıcıları seçenekleri artık bir komut satırı arayüzünün kuralları ile ilgili değildir.
Brandin

5
Ve lütfen. Çıktınızı ekran için biçimlendirirseniz, bir çıktı biçimi geçersiz kılma ekleyin. Hiçbir şey beni bir komut dosyasında kullanmaya çalıştığımda satırları kesen veya saran komutlardan daha fazla rahatsız etmez.
Sobrique

68

Bir veri formatı sözleşmesinin popüler olması onun avantajıdır.

Bir ayırıcı olarak = veya: veya '' kullanmanın, bilgisayar tarafından birbirlerine çok az çabayla dönüştürülebilen önemsiz farklar olduğunu kolayca görebilirsiniz. Ne olurdu büyük çaba bir insan hatırlamak içindir "bu Seyrek kullanılan bir program şeyler sınırlamak yaptım bakınız Şimdi :ya ile =? Hmmm ..."

Başka bir deyişle, Tanrı aşkına, zorlayıcı bir sebep olmadan son derece sağlam sözleşmelerden sapma. İnsanlar, programınızı "kolej denememi kurtaran" yerine "garip ve sinir bozucu cmdline sözdizimine sahip olan" olarak hatırlayacaklar.


19
hemen hemen tüm diller için komut satırı argümanlarını işlemek için kütüphane işlevleri vardır. Onlardan birini kullan.
kevin cline

9
İyi tavsiye, ama bu sözleşmeler nedir? -1
RubberDuck

14
Bu sözleşmeyi bilerek ihlal eden yaygın olarak kullanılan bir UNIX aracının ilginç bir örneği vardır: ddbir key=valuesözdizimi kullanır . Bu tasarım kararının nedeni, bu aracın (takma ad: d ata d estroyer) yanlış kullanıldığında çok fazla hasara yol açabileceğidir. Kullanıcıyı alışılmış alışkanlıklarından vazgeçmeye zorlayarak kullanıcıyı yaptıkları hakkında daha yakından düşünmeye zorlar.
Philipp

18
Bunun sebebinin bu olduğundan emin misin dd? Çekirdeğin ARG_MAX'sinin küçük olduğu, kabukları otomatik tamamlamadığı ve --long-argumentsolmadığı bir zamanda (1970'lerde?) Kodlandığına inanıyorum. O zaman daha iyi beri ddgeriye uyumlu kalmıştır
Basile Starynkevitch

9
ddIBM’in OS / 360’ındaki bir betik dili (JCL) olan ve sözleşmelerin farklı olduğu, başka bir işletim sisteminden (JCL) IBM’in OS / 360’ına yerleştirilmeden önce - kısmen kullanması muhtemel olanların bildiği gibi önceki sistem.
Baard Kopperud

29

Layman açısından

Roma'da romalılar gibi davran.

  • CLI uygulamanız Linux / Unix'e yönelikse, -p valueveya --parameter valuekurallarını kullanın . Linux, bu tür parametreleri ve bayrakları kolay bir şekilde ayrıştırmak için araçlara sahiptir.

Genelde böyle bir şey yaparım:

while [[ $# > 0 ]]
do
key="$1"
case $key in
    --dummy)
    #this is a flag do something here
    ;;
    --audit_sessiones)
    #this is a flag do something here
    ;;
    --destination_path)
    # this is a key-value parameter
    # the value is always in $2 , 
    # you must shift to skip over for the next iteration
    path=$2
    shift
    ;;
    *)
    # unknown option
    ;;
esac
shift
done
  • CLI uygulamanız Windows için tasarlandıysa, kullanımı /flagve /flag:valuekuralları.

  • Oracle gibi bazı uygulamalar da kullanmaz. Oracle yardımcı programları kullanır PARAMETER=VALUE.

  • Yapmayı sevdiğim şeylerden biri, komut satırındaki parametreleri kabul etmenin yanı sıra, uzun parametre zincirlerinden kaçınmak için bir anahtar-değer çifti dosyası olan bir parfile kullanma seçeneği sunmaktır . Bunun için ek bir --parfile mifile.parparametre sağlamalısınız . Açıkça --parfilekullanılırsa, diğer tüm parametreler parantez içinde ne olduğuna göre atılır.

  • Ek bir öneri bazı özel ortam değişkenlerinin kullanımına izin vermektedir, örneğin, ortam değişkeninin MYAPP_WRKSPACE=/tmpayarlanması her zaman ayarlanmasını gereksiz kılacaktır --wrkspace /tmp.

  • Linux'ta otomatik parametre tamamlama parametresi eklemeyi unutmayınız , yani kullanıcılar yarım anahtar yazabilir, isabet alabilir TABve kabuk onlar için tamamlar.

1
Pek çok GNU yardımcı programı (örn. gcc) Önerileriniz @mifile.pargibi işlemektedir --parfile mifile.par.
Basile Starynkevitch,

7
Bir parametre dosyası varsa diğer tüm seçenekleri yoksaydığınızdan emin misiniz? En iyi ihtimalle bana karşı sezgisel geliyor.
Jonathan Leffler,

8
Jonathan ile parametre dosyaları konusunda hemfikirim. Parametre dosyası mevcutsa, varsayılan değerler için kullanılmasını bekliyorum, komut satırında verilen argümanlarla parfile'dekinin üstüne. Bazı nedenlerden dolayı bir parfile kullanımı ek komut satırı argümanlarının kullanılmasını engelliyorsa, o zaman ek argümanların varlığı bir hata olmalıdır.
Eldritch Cheese

@EldritchCheese Yazdığım CLI uygulamalarında, bir parfile verildiğinde, herhangi bir koşullu parametre bir hata oluşturur.
Tulains Córdova

1
Yetenekli bir kabuk kullanılıyorsa, bu tür bir "config dosyası parametresi" seçeneği gerekli değildir. örneğin, sadece yazıyorsun fooCmd -opt1 -opt2 $(cat more_options.opts). Bu nedenle, eğer sağlandıysa, temelde aynı şekilde çalışacak bir "config dosyası parametresi" seçeneğinin olmasını beklerdim.
Brandin

19

Henüz gelmeyen bir şey:

Yazılımınızı komut satırı argümanlarından yukarı doğru tasarlamaya çalışın . Anlamı:

İşlevselliği tasarlamadan önce kullanıcı arayüzünü tasarlayın.

Bu, erken davaları ve genel davaları daha erken incelemenizi sağlar. Tabii ki hala dışını ve içini soyutlayacaksınız, ancak tüm kodu yazmaktan ve daha sonra bir CLI'yi çarpmaktan çok daha iyi sonuç verecek.

Dahası, docopt'a göz atın ( http://docopt.org/ ).

docopt, birçok dilde, özellikle de çok kısıtlı olduğunuz python için, argparse gibi kullanıcı-ters argüman ayrıştırıcılarının hala "OK" olarak kabul edildiği için büyük bir yardımcıdır. Ayrıştırıcı ve alt ayrıştırıcı ve koşullu sözler kullanmak yerine, sadece sözdizimi yardımını tanımlarsınız ve gerisini halleder.


Bu cevabı seviyorum ve bunun için teşekkür ederim, çünkü şu anda argparsehiçbir programcı, kullanıcı arayüzü veya kullanıcı dostu olmaktan dolayı hayal kırıklığına uğradım .
kedi

Docopt'u denedim ve bundan hoşlanmadım. Alt komutlarınız varken seçeneklerle ilgili biraz sıkıntı olmasına rağmen, daha temiz kodda sonuçlara tıklayın .
jpmc26

2
Bu bir reklam gibi çok fazla. İlgili olursa, yalnızca bir kez kaynaktan bahsedin. Ancak şimdi olduğu gibi, cevabınızın% 50'si yalnızca harici bir kaynağı tanıtmak gibi görünüyor.
Brandin'de

'Önce kullanım modelini tasarla' 'olarak adlandırırdım. Kullanıcı deneyimini işlevsellikten ayırmak birçok durumda yapay bir ayrım olabilir (araç sınırlamaları arayüzü etkiler).
copper.hat

1
Docopt için +1. Bütün CLI ikilemlerimi tamamen acısız çözdü. Bazen hakiki coşku gelen reklam söylemek zor, ama burada öyle - Ben herhangi bir şekilde bağlantısı olmayan, yıllardır bir Docopt meraklısı olmuştur;)
frnhr

3

Zaten verilen bazı değerli yorumlar (@Florian, Basile), ama ekleyeyim ... OP diyor ki,

Cihazları yönetmek için ön uç arayüz sağlayacağız. Ancak, bazı gelişmiş yöneticiler uygulamayı kendi başlarına yapılandırmak isteyebilir.

Ama aynı zamanda şunu da söyler:

Bu sorunun platform veya dile özgü olmasını istemedim

Hedef kitlenizi - ileri düzey yöneticileri göz önünde bulundurmalısınız . Normalde hangi platformda çalışıyorlar - Win / Unix / Mac? Peki hangi platformda çalışıyorsunuz? Bu platform için zaten kurulmuş olan CLI sözleşmelerini izleyin. "Gelişmiş" yöneticileriniz GUI tabanlı bir araç istiyor mu / istiyor mu?

Arayüzün dahili olarak ve diğer yönetici araçlarıyla tutarlı olmasını istiyorsunuz. Durup düşünmek istemiyorum cmd -p <arg>ya cmd -p:<arg>da ya da cmd /p <arg>. Tırnaklara ihtiyacım var mı? Çünkü bir boşluk var? Yapabilir miyim cmd -p <val1> <val2>veya cmd -p <val1> -p <val2>birden fazla hedef için mi? Siparişe özel mi? Overloadable? Does cmd -p2 <arg> -p1 <arg>çok çalışmak? Does ls -l -r -t dir1 dir2== ls -trl dir1 dir2?

Unix yönetici araçlarım için, Heiner's Shelldorado tarafından verilen rehberliği , belirtilen diğer referansları da göz önünde bulundurarak her zaman sakladım .

CLI'yi tasarlamak kadar önemlidir, uygulamanızın GUI'dekiyle aynı komut satırı argümanlarıyla çalışacak şekilde tasarlandığından emin olmaktır - yani: GUI'de iş mantığı yoktur veya hem GUI hem de CLI denilen ortak komutu kullanın.

Çoğu UNIX tabanlı yönetim aracı aslında ilk önce komut satırı araçları olarak tasarlanmıştır ve sağlanan GUI, yalnızca komut satırı seçeneklerini "doldurmayı" kolaylaştırır. Bu yaklaşım otomasyona, cevap dosyalarının kullanılmasına, vb. Ve hands-off yönetimine izin verir (benim için daha az iş!)

Klasik araç takımı olarak kullanılan bu yaklaşım Tcl / Tk'dir . Takım değiştirmenizi önermemek; tasarım yaklaşımını ilk önce uygulamaya GUI tabanlı bir yönetim uygulaması yazmaktan önce komut satırı aracı olarak düşünün; daha sonra kolaylık olması için GUI'yi üste katlayın. Bir noktada, birden fazla yapılandırma yapmanız ve genellikle aynı seçenekleri tekrar tekrar tekrar girmeniz gerekirse, GUI'nin acı verici (ve hataya açık) olduğunu keşfedeceksiniz ve otomatik bir yaklaşım arayacaksınız.

Yöneticinizin yine de doğru kutulara doğru değerleri yazması gerektiğini unutmayın, bu nedenle GUI ile ne kadar çaba harcamaktasınız?


Harika, evet! Bir soru da: i çalıştırabilirsiniz ./this-script --hosts <Host.txt
Florian Heigl
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.