Parsing your script's command line - PerlMonks

文章推薦指數: 80 %
投票人數:10人

This tutorial describes how to deal with information passed in on the command line. Not the switches passed to the Perl interpreter, but the switches and ... goahead...beaheretic   PerlMonks   Parsingyourscript'scommandline bygrinder(Bishop) Log inCreate a new user The Monastery Gates Seekers of Perl Wisdom Meditations Cool Uses For Perl Obfuscation Tutorials Poetry Reviews Perl News Donate Recent Threads Newest Nodes Super Search PerlMonks Discussion What's New onJun14,2001at02:04 UTC (#88222=perltutorial:printw/replies,xml) NeedHelp?? Thistutorialdescribeshowtodealwithinformationpassedinon thecommandline.NottheswitchespassedtothePerlinterpreter, buttheswitchesandfilenamesthatarepassedtoyourscript. Thefirststeps Let'sassumethatyouhavewrittenyourfirsthelloworldscript, whichlookssomethinglikethis: #!/usr/local/bin/perl-w print"Hello,world\n"; [download] Insteadofgreetingtheworld,youwouldliketogreetwhateveris passedinonthecommandline.Todothat,youshouldknowthatthe [email protected] atthefirstelement,wecouldindexitusing$ARGV[0].The usualidiom,however,istoremovetheelementfromthearrayandthen dealwithitand/orthrowitway.shiftisusedtogetatthefirst elementofanarray,thuswewouldwritesomethinglike: #!/usr/local/bin/perl-w usestrict; my$thing=shift(@ARGV); print"Hello,$thing\n"; [download] Asitturnsout,Perloffersaconvenientshort-cut.Ifyouuse shiftoutsideasubroutinecontextwithnoparameters,itwill implicitlyuse@ARGV,sotheabovecanberewrittenas: #!/usr/local/bin/perl-w usestrict; my$thing=shift; print"Hello,$thing\n"; [download] ThisiswillbefamiliartopeopleusedtoUnixshellprogramming.This isallwellandgood;thescript'sbehaviouriscontrolledby theparametersappearingonthecommandline.Thereisaproblem, however,inthatnowaparametermustbesupplied,forifitis omitted,thescriptwillcoughupaUseofuninitializedvaluein concatenationerror,andallthatwillbeprintedis"Hello,". Usingdefaultvalues Itwouldbenicetobeabletoprovidethescriptwithasensible defaultvalue,sothatshouldnoparameterbesupplied,itwillbeable tocontinueanddosomethingreasonable.Forthiswecanusethe|| operator: #!/usr/local/bin/perl-w usestrict; my$thing=shift||'world'; print"Hello,$thing\n"; [download] Whatthisdoesisassign$thingthevalueofthefirst parameteronthecommandlineor'world',shouldthecommandlinebe empty.Ofcourse,sometimesanemptycommandlineisnotreasonable,in whichcasethebestthingistostopthescriptandprintoutamessage sothattheusercantakecorrectiveaction: #!/usr/local/bin/perl-w usestrict; my$thing=shiftordie"Nothingspecifiedonthecommandline.\n"; print"Hello,$thing\n"; [download] Notethatthecorrectidiomsaretosayshift||$valuebut shiftordie.ReaduponPerl'sprecedencerulestounderstand why. There'sanothergotchatobeawareof,ifever0isa validvaluetopassinonthecommandline: my$thing=shift||'default'; [download] ...willnotdotherightthingifyoupass0tothescript. ItboilsdowntowhatPerlconsiderstruth.Itjustso happensthat0istreatedasfalse,sothelefthandsideofthe ||operatorasawholeisfalse,andthus$thing windsupbeingassignedthevalueof'default'. Thereisasimpletwostepprocesswayaroundthis.Firstassignwhat comesoutofshift.Then,dependingonwhether$thing isdefined(notwhetheritistrueorfalse,thusside-steppingthe issue),usethewonderful-but-cryptic||=topossibly assignto$thing,basedontheoutcomeoftheconditional. my$thing=shift; $thing||='default'unlessdefined$thing; [download] Introducingcomandlineswitches Nowsupposingwewantedtomodifythescripttosay"Goodbye" accordingtowhetherthe-gswitchwasused.Wewouldliketosay thingslike: greet greetsailor greet-g greet-g'cruelworld' LetusfirstconsiderTheWrongWaytodoit: #!/usr/local/bin/perl-w usestrict; my($switch,$thing); $switch=shift; if($switchand$switcheq"-g"){ $thing=shift||'world'; }else{ $thing=$switch||shift||'world'; $switch=undefif$switch; } print$switch?'Goodbye':'Hello',",$thing\n"; [download] Theabovecodeisdifficulttounderstand.Itdoes,however,work accordingtospec.Themainproblemisthatitwillfailtoconsider -tor-anythingasaswitch,andcomplainthatthe switchhasnoeffectontheprogram.Forexample,considerwhatgreet -hharrywillprintout.Evenworse,thecodewillbecomehorribly obfuscatedshouldthescripthavetodealwithtwo,threeormorecommand lineswitches. Obviously,abetterapproachiscalledrequired.Aboveall,itwould benicenottohavetowriteitoneself,butratherusesomethingthat existsalready.Thatmustmeanthatpackagesexisttodowhatweneed. Whatwearelookingforissomethingthatwilllookforswitch-like instancesonthecommandline,setsomecorrespondingPerlvariablesand aboveallremovethemfrom@ARGVsothatwedon'thavetobother withthem. Whatcanperloffer? NotethedistinctionbetweenPerlthelanguageandperlthe interpreter.Asitturnsoutperl,thePerlinterpretercandosomerudimentary commandlineprocessingallbyitself.Sometimesthisissufficient.All youhavetodoisfeedtheinterpreterthe-sswitch: #!/usr/local/bin/perl-sw usestrict; usevarsqw/$g/; my$thing=shift||'world'; print$g?'Goodbye':'Hello',",$thing\n"; [download]

Nowwehaveamuchsmallerscriptthatshouldbeeasierto understand.Thereis,however,asmallproblemduetointeractionswith usestrictpragma.The-sfunctionalityharksbackto beforetheageoflexicalvariables.Itreferstopackagevariablesthat havetobeexplicitlydeclaredinausevarspragmawhen strictisinuse.Thisisnotreallyaproblem,exceptthat ifthescriptisrunwiththe-hswitchandwarningsareswitchedon, theprogramwillcompletebutitwillspitoutaName"main::h" usedonlyonce:possibletypo.warningmessage. Beforeturningawayfrom-sasaviablesolution,consider theotherfeaturethatPerlprovides.Iftheabovescriptisrunwith -g,thepackagevariable$gissetto1.Alternatively, thescriptcouldberunwith-g=foo,inwhichcaseinsteadof beingsetto1,$gwouldcontain'foo'.Sometimesthislimited functionalityisenoughtogetthejobdone,andthefactthatyoudon't havetodragaroundanexternalpackagefilecanbeawinincertain circumstances. Itappearsthat -shassomerathernastysideeffects,whichmeansthatscriptsthatuseitshouldonlybeusedinsafelycontrolledenvironments(ifsuchathingexists).Formoreinformation,readthethread"perl-sisevil?". getopt:theheavyartillery MoreUnixculture:thetraditionalwaytoparsecommandlinearguments inCwasthroughalibrarycallnamedgetoptorgetopts, shortforgetoptions.ThishasbeencarriedovertoPerlinthe formofGetopt::StdandGetopt::Longwhicharebundled inthecoredistribution. Getopt::Std Getopt::Stdperformscommandlineprocessingandpulls outanythingthatresemblesa-letterswitchanditsvalue,leaving [email protected], getoptandgetopts.Youalmostalwayswanttousethe secondvariant.Let'sseewhy: #!/usr/local/bin/perl-w usestrict; useGetopt::Std; usevarsqw/$opt_g/; getopt('g'); my$thing=shift||'world'; print$opt_g?'Goodbye':'Hello',",$thing\n"; [download] Beforegoinganyfurther,thefirstthingtopointoutisthat Getopt::Stdhasbeenretrofittedtogetaroundtheuncomfortable useofpackagevariables.Ifyoupassareferencetoahashasthe secondparametertothegetoptcall,itwillpopulatethe hash,insteadofusingpackagevariables,whichallowsthescripttobe rewrittenas: #!/usr/local/bin/perl-w usestrict; useGetopt::Std; my%args; getopt('g',\%args); my$thing=shift||'world'; print$args{g}?'Goodbye':'Hello',",$thing\n"; [download] Thisscriptwillsilentlyignoreanon-specifiedswitch,which isusuallyAGoodThing.Thereis,however,aseriousbuglurkingin thiscode.Trytogetthescripttoprint"Goodbye,foo".It'srather difficulttodobecausegetoptisgreedy.Whenitsees aspecifiedswitch,ittrieshardtoassignthatswitchameaningful value,whichmeanseitherthecharactersfollowingtheswitch(asin -gparam)orthenextparameteronthecommandline (asin-gparam).Whichmeansifyouruntheabovescriptas script-gfoo,$arg{g}willcontain'foo',butthere willbenothingleftonthecommandline,so$thingwillbe assignedthedefaultvalueof'world'. Inordertogetaroundthis"feature",thesecondinterface,via getoptsshouldbeusedinstead.Inthiscase,thespecification string('g'intheabove)isinterpreteddifferently.Bydefault,all lettersspecifybooleanparameters.Toforceaparametertopickup avalue(i.e.togetthebehaviourwesomuchwantedtoavoid above),a':'(colon)isappended.Therefore,tomake-g greedy,itshouldbespecifiedas'g:'. Thismeansthatallwehavetodointheabovescriptistocall getoptsinsteadofgetoptandthejobisdone. Ifyouwanttolookatareal-lifeexampleofcodethat usesGetopt::Std,youcanlookatascriptIuploaded herenamedpinger,alittletooldesigned toscanarangeofIPaddressesviaping. Getopt::Long Thatisallwellandgood,butwhathappenswhenyoureimplement tarin Perl?Howdoyourememberwhatallthosepeskysinglecharacterswitches dointhestring-cznTfoo?It'smucheasytounderstandwhat's goingonwith--create--gzip--norecurse--files-fromfoo instead.EnterGetopt::Long. Thismoduleletsyoubuildupaspecificationthatadherestothe POSIXsyntaxforcommandlineoptions,whichgenerallyintroduces switcheswiththedouble-dashnotation.Unfortunately,thisprecludes theuseofsingle-dashswitches(bikeNomadpointsoutthatthisisnottrue.Mybadfornotpayingcloserattention tothedocumentation).Evenworse,youcannotincludeboth Getopt::StdandGetopt::Longinthesameprogram, [email protected]. SinceIoriginallywrotethistutorial,IhaveusedGetopt::Longabitmore(figuredthatIhadtosinceIwrotethis).OnceyouunderstandGetopt::Simple,Getopt::Longisprettyeasytopickup,andhasmuchsophisticationtooffer,onceyouscratchbelowthesurface. Thatsaid,alloftheprocessinggoesonbehindthescenes.Youcanattachacallbacktodealwiththeprocessingofindividualoptions,butthiscanbecomeunwieldy.Sometimesyouneedmorefine-grainedcontroloftheparsingoftheswitches,astheycomeinonebyone. Whilethefollowingmoduleisnolongerbeingactivelydeveloped,itisjustwhatyouneedinsomeinstances,becauseitdealswithparsingoptionsonly,andletsyoudealwiththerest.Itturnstheparsinginsideout,andletsyouactonoptionsonthefly,andjustthereforefeelsmorecooperative.Tryit,youmightlikeit. Getopt::Mixed Thismoduleshouldcoverallyourcommandline processingneeds.It'squitesimpletosetup.Firstofallyouneedto callinitwithaformatstring(akintopackandunpack).Thesetsup whatcommandlineswitchesaredefined,andwhatvaluestheycantakeon. Here'sareallifeexamplehoistedfromsomecodeIhavelyingaround: Getopt::Mixed::init('j=sl:sp=is=st=slogfile>ld>pdate>pperiod> +pproject> jtype>t'); [download] Thisencodesthefollowinginformation: -j,-sand-ttakeamandatorystringargument. -ltakesanoptionalstringargument -ptakesamandatoryintegerargument --logfileisanaliasfor-l -d,--dateand--periodareallaliasesfor -p undsoweiter. Prettystraightforwardstuff.ThenextstepistocallnextOption repeatedlyuntilitfails.Oncethatisdone,youhaveprocessedallthe switches.UnlikeGetopt::Stdyousetyourdefaultsbeforehand.Ifthe switchisn'tspecified,thevalueisn'ttouched.Alsonotethatjustbecausea switchhasamandatoryargumentdoesn'tmeanthatthescriptwillabortif theswitchdoesn'tappearonthecommandline...it'snottheswitchitself thatismandatory.Ifthisisrequiredthenyoutestthecorresponding variableaftertheloopandifitsvalueisundefinedthenyouyanktherug outfromunderthescript. Theprocessinglooplookssomethinglikethis: while(my($option,$value,$pretty)=Getopt::Mixed::nextOption() +){ OPTION:{ $optioneq'j'anddo{ $Project=$value; lastOPTION; }; $optioneq'l'anddo{ $Logfile=$valueif$value; lastOPTION; }; #... } } Getopt::Mixed::cleanup(); die"Noprojectspecifiedvia-j.\n"unless$Project; [download] Themoduleissmartenoughtorecognise -jfoo -jfoo -j=foo asallbeingvalidsyntaxesforassigningfootothe -jswitch.Rememberthelastvariant.It'sthe easiestwayofpassinginanegativenumberonthecommand line.Afterall,howshould--offset-30be interpreted? Anotherreal-lifeexampleofcode,thistimeusing Getopt::Mixedcanbefoundatnugid,a scriptIwrotetomanagelargescalemodifications ofuidsandgidsofUnixfilesystems. Wheretofromhere Thisshouldbeenoughfor95%ofyourbasiccommandlineprocessing needs.Buteveryonehasadifferentitchtoscratch,andyoushouldbe awarethatthereisaboatloadofgetoptishpackageshangingouton CPAN,asasearchwillreveal.Onceyouhavethehangofacoupleit's prettysimpletopickupanother. Themostsophisticatedofall,Getopt::Declarecomes, naturallyenough,fromtheDamian. Thismodulehasanadvancedmethodforspecifyingexactlywhatarethe legalvaluesthataswitchmaytake,aswellasprovidingpoddishdescriptions sothatyoudon'thavetowritesubusage{...}thatexplains howtousetheprogramcorrectly. Switchnameidioms Overtheyears,anumberofconventionshavearisenoverthebestletters toassigntocommonoperationsthatcropupagainandagaininprogram design.Thislistattemptstocodifyexistingpractices(updateswelcomed). Usetheseconventionsandpeoplewillfindyourprogramseasytolearn. -aProcesseverything(all). -dDebugmode.Printoutlotsofstuff. -hHelp.Printoutabriefsummaryofwhatthescriptdoesandwhatitexpects. -iInputfile,orincludefile -lNameoflogfile -oNameofoutputfile -qQuiet.Printoutnothing. -vVerbose.Printoutlotsofstuff. Andnowyouknowallyouneedtoknowaboutcommandlineprocessing. Havefun! update:Tipo'thehattopetralforpointingout thenodeonGetopt::Declare,-handabetter Damianlink.Tipo'thehattoAlbannachforreminding meaboutthe"passing0onthecommandline"bugaboo,and toOeufMayoregardingpassingnegativenumbers. CommentonParsingyourscript'scommandlineSelectorDownloadCode Repliesarelisted'BestFirst'. Re:Parsingyourscript'scommandline bybikeNomad(Priest)onJun14,2001at06:35 UTC Nicetutorial.Oneminordisagreement,though:Getopt::Longisquitehappywithsingle-characterswitches.Ifyouwanttobundlethem(asin,'-vax'meansthesameas'-v-a-x'),youhavetocall:Getopt::Long::Configure("bundling"); [download] [reply][d/l] Re:Parsingyourscript'scommandline bymugwumpjism(Hermit)onJun14,2001at14:46 UTC YoushouldalsochecktoseeifyouroptionislistedintheGNUCodingStandardsOptionTable.Don'tforgettosupport--helpand--version! Otherthanthat,niceintro.[reply] Re:Re:Parsingyourscript'scommandline byxphase_work(Pilgrim)onJun14,2001at18:38 UTC ThatstatementonlyappliestoGNU/Linuxsystems,oratleastsystems thatusetheGNUBinutils.MostcommercialUNIXvendorsdon'thave longoptionsupportintheirBinutils.SunandHP'sversionsoftardon't supportlongarguments,butFreeBSDandLinuxsupportbothformsof arguments. Whilethechoiceofwhichargumentsyourprogramsacceptisyourchoice, manypeoplechoosetofollowthestandardtheirOSvendoruses. Ithinkthatthetableshowingonlytheshortargumentsisgood becauseshortargumentsismoreofastandardthenGNU-Stylearguments, butIthinkthatincludingalinktoGNUCodingStandardsOptionTable, withanexplainationthattheseareusedmainlyonGNU/LinuxorGNUBinutils systemswouldbeuseful. -xPhase[reply] Re:Re:Re:Parsingyourscript'scommandline bymugwumpjism(Hermit)onJun14,2001at23:20 UTC Ah,butthisisPerl,you'resupposedtobethinking crossplatform.AndwhatismorecrossplatformthanGNU? I'drecommendlookingatthetable,andusingwhat'son thereunlessyouhaveagoodreasonnotto.[reply] Re:Parsingyourscript'scommandline byNot_a_Number(Prior)onAug14,2003at18:07 UTC Verynice,++ However,Ihaveasmallquestiononthissnippet: my$thing=shift; $thing||='default'unlessdefined$thing; [download] Surelythe||isredundanthere? my$thing=shift; $thing='default'unlessdefined$thing; [download] Thisseemstodothejobjustaswell? OramImissingsomething? thx dave[reply][d/l][select] Re:Re:Parsingyourscript'scommandline byyosefm(Friar)onSep04,2003at11:48 UTC Thisisbecause$thingcouldbedefinedbutzeroandwedon'twanttooverwriteaperfectlyvalidzerofromthecommandline.[reply] Re:Re:Re:Parsingyourscript'scommandline byNot_a_Number(Prior)onSep04,2003at20:17 UTC Er... I'mafraidIdon'tunderstand.Underwhatcircumstancesdoes: $thing='default'unlessdefined$thing; notworkfor$thing==0?I'mconfused.Couldyoushowmesomecodewherethebehaviouroftheabovediffersfrom: $thing||='default'unlessdefined$thing; Thanksinadvance, dave [reply][d/l][select] Re^3:Parsingyourscript'scommandline byJadeNB(Chaplain)onSep07,2008at20:16 UTC Thisisbecause$thingcouldbedefinedbutzeroandwedon'twanttooverwriteaperfectlyvalidzerofromthecommandline. AsNot_a_Numberpointsout,thesyntaxEXPRunlessdefined$thingwilldonothingatall*if$thingisdefined,whetherit'strueorfalse.Thatis,ifweareexecutingEXPR,then$thingisguaranteedundefined,hencefalse;so$thing||='default'isguaranteedtobethesameas$thing='default'. Itseemsreasonabletoguessthatwhathappenedisthatthecoderoriginallyhad$thing||='default'insomeoldcode,discovered(asyoumention)thatitdoesn'tworkwhen$thingisfalse-but-defined,andaddedthedefinedcheckwithoutrealisingthatitmade||=redundant. Ofcourse,amerefiveyearslater,wehavethewonderful//=(CstyleLogicalDefinedOr)insteadtosaveusthispain. UPDATE(the*'dstatementabove—sorry,Idon'tknowhowtodofootnotes):Onfurtherthought,it'snotquitetruethatEXPRunlessdefined$thingwilldonothingif$thingisdefined.AmongwhatIsupposearemanyothersubtlecases,iftheunlessisthelastlineinasubroutine,it'llmakethesubroutinereturn1when$thingisdefined.Forexample,after our$a=1; subb{0unlessdefined$a} subc{} my$b=b; my$c=c; [download] wehavethat$b=1but$cisundefined.[reply][d/l][select] Re:Parsingyourscript'scommandline byAnonymousMonkonMar04,2005at14:42 UTC Verynicetutorial.Helpedmealot.Exspeciallyididn'tsawanoteintheCPANGetOpt:Stddocsthatsaid"GetOpsstripsofallparametersfrom@ARGVandleavestherest". Butthatsreallyimportantifyouwanttouse<>toprocesssomefilesspecifiedonthecommand-line. Sothanxforthework=) GreetingsFromMunich, GrandApeiron[reply] Backto Tutorials LogIn? Username: Password: rememberme What'smypassword? CreateANewUser DomainNodelet? www.com|www.net|www.org NodeStatus? nodehistoryNodeType:perltutorial[id://88222]help Chatterbox? andallisquiet... HowdoIusethis?|OtherCBclients OtherUsers? OthersscrutinizingtheMonastery:(4)GrandFather eyepopslikeamosquito Tux Bod Asof2022-10-2222:05GMT Sections? SeekersofPerlWisdom CoolUsesforPerl Meditations PerlMonksDiscussion CategorizedQ&A Tutorials ObfuscatedCode PerlPoetry PerlNews about Information? PerlMonksFAQ GuidetotheMonastery What'sNewatPerlMonks Voting/ExperienceSystem Tutorials Reviews Library PerlFAQs OtherInfoSources FindNodes? NodesYouWrote SuperSearch ListNodesByUsers NewestNodes RecentlyActiveThreads SelectedBestNodes BestNodes WorstNodes SaintsinourBook Leftovers? TheSt.LarryWallShrine BuyPerlMonksGear OfferingPlate Awards RandomNode Quests Craft Snippets CodeCatacombs EditorRequests blogs.perl.org Perlsphere PerlWeekly Perl.com PerlJobs PerlMongers PerlDirectory Perldocumentation MetaCPAN CPAN VotingBooth? Mypreferredwaytoholiday/vacationis: Visitforeigncountries/cities Relaxataresort Takeacruise Gotovisitfarawayfamily Getawayfromcivilization(e.g.camping,hiking,etc.) Wanderaroundmyowncountry/region(byanypreferredmeansofconveyance) Workonasideproject(e.g.homeimprovement,side-hustle,etc.) Digitalentertainment,astockedfridge,andbeingavoluntaryshut-in What'saholiday/vacation? Other(pleasecomment)Results(67votes).Checkoutpastpolls. Notices? PerlMonksparthenogeneticallyspawnedbyTimVroom. PerlMonkswentonacoupledates,andthendecidedtoshackupwith ThePerlFoundation. BeefyBoxesandBandwidthGenerouslyProvidedby pairNetworks BuiltwiththePerlprogramminglanguage.



請為這篇文章評分?