reinventing the wheel - Parsing command line arguments in Perl
文章推薦指數: 80 %
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<
延伸文章資訊
- 1reinventing the wheel - Parsing command line arguments in Perl
Supports command line arguments in arbitrary order; Supports using -- to use any following argume...
- 2Recipe 15.1. Parsing Program Arguments
Parsing Program Arguments. Problem. You want to let users change your program's behavior by givin...
- 3Processing command line arguments - @ARGV in Perl
Unfortunately there is not a lot we can do when parsing @ARGV "manually". In another article I'll...
- 4How can I parse command line arguments? - perl
I want to parse a list of arguments in a perl script, for example i have this situation :
- 5How Can I Parse Command Line Arguments in Perl?
Perl passes command line arguments to a script using the built-in @ARGV array. This variable does...