reinventing the wheel - Parsing command line arguments in Perl

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

Supports command line arguments in arbitrary order; Supports using -- to use any following arguments "as is", without parsing; Stop parsing and ... CodeReviewStackExchangeisaquestionandanswersiteforpeerprogrammercodereviews.Itonlytakesaminutetosignup. Signuptojointhiscommunity Anybodycanaskaquestion Anybodycananswer Thebestanswersarevotedupandrisetothetop Home Public Questions Tags Users Companies Unanswered Teams StackOverflowforTeams –Startcollaboratingandsharingorganizationalknowledge. CreateafreeTeam WhyTeams? Teams CreatefreeTeam StackOverflowforTeamsismovingtoitsowndomain!Whenthemigrationiscomplete,youwillaccessyourTeamsatstackoverflowteams.com,andtheywillnolongerappearintheleftsidebaronstackoverflow.com. Checkyouremailforupdates. Teams Q&Aforwork Connectandshareknowledgewithinasinglelocationthatisstructuredandeasytosearch. LearnmoreaboutTeams ParsingcommandlineargumentsinPerl AskQuestion Asked 8yearsago Modified 8yearsago Viewed 4ktimes 6 \$\begingroup\$ IusethisidiomtoparsecommandlineargumentsinPerl: my@args; my$encode=1; while(@ARGV){ for(shift(@ARGV)){ ($_eq'-h'||$_eq'--help')&&do{&usage();}; #...moreoptionshere ($_eq'--')&&do{push(@args,@ARGV);undef@ARGV;last;}; ($_=~m/^-.+/)&&do{print"Unknownoption:$_\n";&usage();}; push(@args,$_); } } Thislet'smedothingslike: Supportscommandlineargumentsinarbitraryorder Supportsusing--touseanyfollowingarguments"asis",withoutparsing Stopparsingandprintusagemessageon-h,or--help Raiseerrorifa-somethingflagisdetectedthatisnotmatchedbyanyoftheparsingrules Here'sashortexamplescriptusingthisidiom: #!/usr/bin/envperl usestrict; usewarnings; &usage()unless@ARGV; my@args; my$encode=1; while(@ARGV){ for(shift(@ARGV)){ ($_eq'-h'||$_eq'--help')&&do{&usage();}; ($_eq'-D'||$_eq'--decode')&&do{$encode=!$encode;last;}; ($_eq'--')&&do{push(@args,@ARGV);undef@ARGV;last;}; ($_=~m/^-.+/)&&do{print"Unknownoption:$_\n";&usage();}; push(@args,$_); } } subusage{ $0=~m|[^/]+$|; print"Usage:$&[-h|--help][-D|--decode]\n"; print"\n"; print"Encode(=default)ordecodeBase64\n"; exit1; } useMIME::Base64; if($encode){ printmap(&MIME::Base64::encode_base64($_),@args); }else{ printmap(&MIME::Base64::decode_base64($_),@args); } IsthisagoodtechniqueforparsingcommandlineargumentsinPerl? Isthereabetterway? I'malsointerestedinimprovementideasabouttheshortscriptitselftoo. reinventing-the-wheelperl Share Improvethisquestion Follow editedOct5,2014at7:03 janos askedOct4,2014at22:21 janosjanos 110k1414goldbadges147147silverbadges382382bronzebadges \$\endgroup\$ 1 4 \$\begingroup\$ Whydon'tyouuseastandardPerlpackagesuchasGetopt::StdorGetopt::Long? \$\endgroup\$ – MartinR Oct4,2014at22:39 Addacomment  |  2Answers 2 Sortedby: Resettodefault Highestscore(default) Datemodified(newestfirst) Datecreated(oldestfirst) 2 \$\begingroup\$ Usingthe&sigiltocallasubroutinehasgoneoutofstylesincePerl5wasreleasedin1994. Nestingafor-loopinsideawhile-loopisaweirdwaytoexpresstheflowofcontrol,inmyopinion.Youwanttoiteratethrough@ARGVatmostonce,soitshouldlooklikeasingleloop.Thefor-loopisn'treallyaloopatall;it'sjustawayforlasttogotothepointafterpush(@args,$_).(Theuseofforwouldbeacceptableinconjunctionwiththewhenkeyword,asitwouldthenberecognizableasaPerlswitchstatement.)Ithinkthatthefollowingwaywouldbeaclearerwaytowritetheloop: while(@ARGV){ local$_=shift@ARGV; ($_eq'-h'||$_eq'--help')&&do{usage();}; ($_eq'-D'||$_eq'--decode')&&do{$encode=!$encode;next;}; ($_eq'--')&&do{push(@args,@ARGV);undef@ARGV;next;}; ($_=~/^-./)&&do{printSTDERR"Unknownoption:$_\n";usage();}; push(@args,$_); } Ifasolitary-ispassedonthecommandline,[email protected]'mnotsureifthatisintentional. Explicitlyaskingforusagehelpdiffersfromdisplayinghelpinthecaseofausageerror.Intheformercase,theexitstatusshouldbe0,andthedisplayshouldgotoSTDOUT.Inthelattercase,theexitstatusshouldbenon-zero,andthedisplayshouldgotoSTDERR.Inaddition,Idon'trecommendburyingtheexit()callinsideusage(),becauseitmakesyouroption-parsingloophardertofollow. subusage{ my($status)=@_; my$old_fh=selectSTDERRif$status; print…; select$old_fhif$old_fh; return$status; } exitusage(1)unless@ARGV; while(@ARGV){ local$_=shift@ARGV; ($_eq'-h'||$_eq'--help')&&do{exitusage(0);}; ($_eq'-D'||$_eq'--decode')&&do{$encode=!$encode;next;}; ($_eq'--')&&do{push(@args,@ARGV);undef@ARGV;next;}; ($_=~/^-./)&&do{printSTDERR"Unknownoption:$_\n";exitusage(1);}; push(@args,$_); } Theuseof$encodeisproblematicinthreeways.First,youshouldusevariablesthatreflecttheUI.Also,prefertousevariablesthatdefaultto0orafalsevalue.Finally,toggling$encodewhenevera--decodeflagisencounteredisinappropriate,becauseitissurprisingthat--decode--decodeactuallycausesittoencodeinsteadofdecode.(Imaginewhatwouldhappenifonedefinedashellaliasrmasrm-i,suchthatrunningrm-iexpandstorm-i-i,onlytofindthatfiledeletionisnolongerinteractive!) Inmyopinion,thecodeformattinghindersreadability.Aligningthedoblockswouldhelp.However,youmightaswellbelessstingyandplacestatementsonseparatelines. my$decode; while(@ARGV){ local$_=shift@ARGV; if($_eq'-h'||$_eq'--help'){ exitusage(0); }elsif($_eq'-D'||$_eq'--decode'){ $decode=1; next; }elsif($_eq'--'){ push(@args,@ARGV); undef@ARGV; next; }elsif(/^-./){ printSTDERR"Unknownoption:$_\n"; exitusage(1); }else{ push(@args,$_); } } Theusageofnextandelsifareredundant.Ithinkthattheredundancyhelpsmakethecodeeasiertofollow,butit'samatteroftaste. Share Improvethisanswer Follow editedMay23,2017at12:40 CommunityBot 1 answeredOct5,2014at6:41 200_success200_success 143k2222goldbadges185185silverbadges468468bronzebadges \$\endgroup\$ 3 1 \$\begingroup\$ Thanksforthegreatreview!I'vebeenusingthistechniquesince2005,toobad(asyousay)itwasalreadyobsoletethen:) \$\endgroup\$ – janos Oct5,2014at7:07 1 \$\begingroup\$ Excellentreview.However,it'sperfectlyidiomatictousefornotasaloop,butasatopicalizer(similarinfunctiontoPascal'swithstatement).Doingwhile($_=shift@ARGV){…}isnotnecessarilycorrect:Itdoesnotlocalize$_,andhasproblemswithfalsevalues.Doingwhile(@ARGV){my$flag=shift@ARGV;…}wouldbeoptimal. \$\endgroup\$ – amon Oct5,2014at8:06 \$\begingroup\$ whyareyoustilllocalizing$_?Thereisnobenifitfromitinthatcase.Iwouldunderstand,if,atsomepoint,manyusesofafunctionthatdefaultsto$_isused.butthatwayitjustobscuresthefunctionofthevariable.$argumentorforbrevity'ssake,$argwouldhelp,inmyopinion. \$\endgroup\$ – PatrickJ.S. Oct5,2014at16:50 Addacomment  |  9 \$\begingroup\$ ThereareseveralmodulesonCPANthataremadeforthistask.TheyallresideintheGetoptnamespace.Getopt::Longevencomeswiththestandarddistribution.Socomingtoyourquestion:Yes,therearebetterways. Ifyouareinterestedinsomethingmorefancy,youcouldhavealookatGetopt::Declarewhereyoucanwritetheusagepageandfillyourvariablesinthesameplace.Ithasadownside,thoughsinceitintroducesanotherDSL. WhatIdefinitelywouldrecommendisthatyoutakealookat<



請為這篇文章評分?