Bash: Why is used eval and shift in a script that parses command line arguments?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
2
down vote

favorite
3












As I was looking this answer https://stackoverflow.com/a/11065196/4706711 in order to figure out on how to use parameters like --something or -s some questions rised regarding the answer's script :



#!/bin/bash
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long::
-n 'example.bash' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
case "$1" in
-a|--a-long) echo "Option a" ; shift ;;
-b|--b-long) echo "Option b, argument `$2'" ; shift 2 ;;
-c|--c-long)
# c has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
case "$2" in
"") echo "Option c, no argument"; shift 2 ;;
*) echo "Option c, argument `$2'" ; shift 2 ;;
esac ;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
echo "Remaining arguments:"
for arg do echo '--> '"`$arg'" ; done


First of all what does the shift program in the following line:



 -a|--a-long) echo "Option a" ; shift ;;


Afterwards what is the purpose to use the eval command in the following line:



eval set -- "$TEMP"


I tried to comment the line in script mentioned above and I got the following response:



$ ./getOptExample2.sh -a 10 -b 20 --a-long 40 -charem --c-long=echi
Param: -a
Option a
Param: 10
Internal error!


But if I uncomment it it runs like a charm:



Option a
Option b, argument `20'
Option a
Option c, argument `harem'
Option c, argument `echi'
Remaining arguments:
--> `10'
--> `40'









share|improve this question



















  • 1




    Your outputs with and without the comment are the same. Is that the problem?
    – muru
    Aug 4 '17 at 7:17










  • Fixed it! Thanks for noticing.
    – Dimitrios Desyllas
    Aug 4 '17 at 7:19














up vote
2
down vote

favorite
3












As I was looking this answer https://stackoverflow.com/a/11065196/4706711 in order to figure out on how to use parameters like --something or -s some questions rised regarding the answer's script :



#!/bin/bash
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long::
-n 'example.bash' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
case "$1" in
-a|--a-long) echo "Option a" ; shift ;;
-b|--b-long) echo "Option b, argument `$2'" ; shift 2 ;;
-c|--c-long)
# c has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
case "$2" in
"") echo "Option c, no argument"; shift 2 ;;
*) echo "Option c, argument `$2'" ; shift 2 ;;
esac ;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
echo "Remaining arguments:"
for arg do echo '--> '"`$arg'" ; done


First of all what does the shift program in the following line:



 -a|--a-long) echo "Option a" ; shift ;;


Afterwards what is the purpose to use the eval command in the following line:



eval set -- "$TEMP"


I tried to comment the line in script mentioned above and I got the following response:



$ ./getOptExample2.sh -a 10 -b 20 --a-long 40 -charem --c-long=echi
Param: -a
Option a
Param: 10
Internal error!


But if I uncomment it it runs like a charm:



Option a
Option b, argument `20'
Option a
Option c, argument `harem'
Option c, argument `echi'
Remaining arguments:
--> `10'
--> `40'









share|improve this question



















  • 1




    Your outputs with and without the comment are the same. Is that the problem?
    – muru
    Aug 4 '17 at 7:17










  • Fixed it! Thanks for noticing.
    – Dimitrios Desyllas
    Aug 4 '17 at 7:19












up vote
2
down vote

favorite
3









up vote
2
down vote

favorite
3






3





As I was looking this answer https://stackoverflow.com/a/11065196/4706711 in order to figure out on how to use parameters like --something or -s some questions rised regarding the answer's script :



#!/bin/bash
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long::
-n 'example.bash' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
case "$1" in
-a|--a-long) echo "Option a" ; shift ;;
-b|--b-long) echo "Option b, argument `$2'" ; shift 2 ;;
-c|--c-long)
# c has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
case "$2" in
"") echo "Option c, no argument"; shift 2 ;;
*) echo "Option c, argument `$2'" ; shift 2 ;;
esac ;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
echo "Remaining arguments:"
for arg do echo '--> '"`$arg'" ; done


First of all what does the shift program in the following line:



 -a|--a-long) echo "Option a" ; shift ;;


Afterwards what is the purpose to use the eval command in the following line:



eval set -- "$TEMP"


I tried to comment the line in script mentioned above and I got the following response:



$ ./getOptExample2.sh -a 10 -b 20 --a-long 40 -charem --c-long=echi
Param: -a
Option a
Param: 10
Internal error!


But if I uncomment it it runs like a charm:



Option a
Option b, argument `20'
Option a
Option c, argument `harem'
Option c, argument `echi'
Remaining arguments:
--> `10'
--> `40'









share|improve this question















As I was looking this answer https://stackoverflow.com/a/11065196/4706711 in order to figure out on how to use parameters like --something or -s some questions rised regarding the answer's script :



#!/bin/bash
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long::
-n 'example.bash' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
case "$1" in
-a|--a-long) echo "Option a" ; shift ;;
-b|--b-long) echo "Option b, argument `$2'" ; shift 2 ;;
-c|--c-long)
# c has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
case "$2" in
"") echo "Option c, no argument"; shift 2 ;;
*) echo "Option c, argument `$2'" ; shift 2 ;;
esac ;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
echo "Remaining arguments:"
for arg do echo '--> '"`$arg'" ; done


First of all what does the shift program in the following line:



 -a|--a-long) echo "Option a" ; shift ;;


Afterwards what is the purpose to use the eval command in the following line:



eval set -- "$TEMP"


I tried to comment the line in script mentioned above and I got the following response:



$ ./getOptExample2.sh -a 10 -b 20 --a-long 40 -charem --c-long=echi
Param: -a
Option a
Param: 10
Internal error!


But if I uncomment it it runs like a charm:



Option a
Option b, argument `20'
Option a
Option c, argument `harem'
Option c, argument `echi'
Remaining arguments:
--> `10'
--> `40'






bash shell-script getopts eval






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 35 mins ago

























asked Aug 4 '17 at 7:12









Dimitrios Desyllas

16313




16313







  • 1




    Your outputs with and without the comment are the same. Is that the problem?
    – muru
    Aug 4 '17 at 7:17










  • Fixed it! Thanks for noticing.
    – Dimitrios Desyllas
    Aug 4 '17 at 7:19












  • 1




    Your outputs with and without the comment are the same. Is that the problem?
    – muru
    Aug 4 '17 at 7:17










  • Fixed it! Thanks for noticing.
    – Dimitrios Desyllas
    Aug 4 '17 at 7:19







1




1




Your outputs with and without the comment are the same. Is that the problem?
– muru
Aug 4 '17 at 7:17




Your outputs with and without the comment are the same. Is that the problem?
– muru
Aug 4 '17 at 7:17












Fixed it! Thanks for noticing.
– Dimitrios Desyllas
Aug 4 '17 at 7:19




Fixed it! Thanks for noticing.
– Dimitrios Desyllas
Aug 4 '17 at 7:19










2 Answers
2






active

oldest

votes

















up vote
3
down vote



accepted










One of the many things that getopt does while parsing options is to rearrange the arguments, so that non-option arguments come last, and combined short options are split up. From man getopt:



Output is generated for each element described in the previous section.
Output is done in the same order as the elements are specified in the
input, except for non-option parameters. Output can be done in
compatible (unquoted) mode, or in such way that whitespace and other
special characters within arguments and non-option parameters are
preserved (see QUOTING). When the output is processed in the shell
script, it will seem to be composed of distinct elements that can be
processed one by one (by using the shift command in most shell
languages).

[...]

Normally, no non-option parameters output is generated until all
options and their arguments have been generated. Then '--' is
generated as a single parameter, and after it the non-option parameters
in the order they were found, each as a separate parameter.


This effect is reflected in your code, where the option-handling loop assumes that all option arguments (including arguments to options) come first, and come separately, and are finally followed by non-option arguments.



So, TEMP contains the rearranged, quoted, split-up options, and using eval set makes them script arguments.



As for shift, it does what it always does: remove the first argument, and shift all arguments (so that what was $2 will now be $1). This eliminates the arguments that have been processed, so that, after this loop, only non-option arguments are left and you can conveniently use $@ without worrying about options.






share|improve this answer




















  • At least in the GNU enhanced getopt, you can prevent the re-ordering of the options list by setting the scanning mode to -. To do this, the first character in the short arguments list should be -, as in -o -ab:c::
    – bobpaul
    Mar 20 at 17:51

















up vote
1
down vote













The script works correctly when it gives you an error for -a 10. The -a option needs no parameter in this script. You should only use -a.



The shift described in the man page as the following:



shift [n]
The positional parameters from n+1 ... are renamed to $1 .... Parameters represented by the numbers $# down to $#-n+1 are unset. n must be a non-negative number less than or equal to $#. If n is
0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters are not changed. The return status is greater than zero if n is greater
than $# or less than zero; otherwise 0.


So basically it drops -a and shift the remaining arguments so the second parameter will be $1 in the next cycle.



-- is also described in the man page:



 -- A -- signals the end of options and disables further option processing. Any arguments after the -- are treated as filenames and arguments. An argument of - is equivalent to --.





share|improve this answer




















    Your Answer








    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "106"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f383862%2fbash-why-is-used-eval-and-shift-in-a-script-that-parses-command-line-arguments%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    3
    down vote



    accepted










    One of the many things that getopt does while parsing options is to rearrange the arguments, so that non-option arguments come last, and combined short options are split up. From man getopt:



    Output is generated for each element described in the previous section.
    Output is done in the same order as the elements are specified in the
    input, except for non-option parameters. Output can be done in
    compatible (unquoted) mode, or in such way that whitespace and other
    special characters within arguments and non-option parameters are
    preserved (see QUOTING). When the output is processed in the shell
    script, it will seem to be composed of distinct elements that can be
    processed one by one (by using the shift command in most shell
    languages).

    [...]

    Normally, no non-option parameters output is generated until all
    options and their arguments have been generated. Then '--' is
    generated as a single parameter, and after it the non-option parameters
    in the order they were found, each as a separate parameter.


    This effect is reflected in your code, where the option-handling loop assumes that all option arguments (including arguments to options) come first, and come separately, and are finally followed by non-option arguments.



    So, TEMP contains the rearranged, quoted, split-up options, and using eval set makes them script arguments.



    As for shift, it does what it always does: remove the first argument, and shift all arguments (so that what was $2 will now be $1). This eliminates the arguments that have been processed, so that, after this loop, only non-option arguments are left and you can conveniently use $@ without worrying about options.






    share|improve this answer




















    • At least in the GNU enhanced getopt, you can prevent the re-ordering of the options list by setting the scanning mode to -. To do this, the first character in the short arguments list should be -, as in -o -ab:c::
      – bobpaul
      Mar 20 at 17:51














    up vote
    3
    down vote



    accepted










    One of the many things that getopt does while parsing options is to rearrange the arguments, so that non-option arguments come last, and combined short options are split up. From man getopt:



    Output is generated for each element described in the previous section.
    Output is done in the same order as the elements are specified in the
    input, except for non-option parameters. Output can be done in
    compatible (unquoted) mode, or in such way that whitespace and other
    special characters within arguments and non-option parameters are
    preserved (see QUOTING). When the output is processed in the shell
    script, it will seem to be composed of distinct elements that can be
    processed one by one (by using the shift command in most shell
    languages).

    [...]

    Normally, no non-option parameters output is generated until all
    options and their arguments have been generated. Then '--' is
    generated as a single parameter, and after it the non-option parameters
    in the order they were found, each as a separate parameter.


    This effect is reflected in your code, where the option-handling loop assumes that all option arguments (including arguments to options) come first, and come separately, and are finally followed by non-option arguments.



    So, TEMP contains the rearranged, quoted, split-up options, and using eval set makes them script arguments.



    As for shift, it does what it always does: remove the first argument, and shift all arguments (so that what was $2 will now be $1). This eliminates the arguments that have been processed, so that, after this loop, only non-option arguments are left and you can conveniently use $@ without worrying about options.






    share|improve this answer




















    • At least in the GNU enhanced getopt, you can prevent the re-ordering of the options list by setting the scanning mode to -. To do this, the first character in the short arguments list should be -, as in -o -ab:c::
      – bobpaul
      Mar 20 at 17:51












    up vote
    3
    down vote



    accepted







    up vote
    3
    down vote



    accepted






    One of the many things that getopt does while parsing options is to rearrange the arguments, so that non-option arguments come last, and combined short options are split up. From man getopt:



    Output is generated for each element described in the previous section.
    Output is done in the same order as the elements are specified in the
    input, except for non-option parameters. Output can be done in
    compatible (unquoted) mode, or in such way that whitespace and other
    special characters within arguments and non-option parameters are
    preserved (see QUOTING). When the output is processed in the shell
    script, it will seem to be composed of distinct elements that can be
    processed one by one (by using the shift command in most shell
    languages).

    [...]

    Normally, no non-option parameters output is generated until all
    options and their arguments have been generated. Then '--' is
    generated as a single parameter, and after it the non-option parameters
    in the order they were found, each as a separate parameter.


    This effect is reflected in your code, where the option-handling loop assumes that all option arguments (including arguments to options) come first, and come separately, and are finally followed by non-option arguments.



    So, TEMP contains the rearranged, quoted, split-up options, and using eval set makes them script arguments.



    As for shift, it does what it always does: remove the first argument, and shift all arguments (so that what was $2 will now be $1). This eliminates the arguments that have been processed, so that, after this loop, only non-option arguments are left and you can conveniently use $@ without worrying about options.






    share|improve this answer












    One of the many things that getopt does while parsing options is to rearrange the arguments, so that non-option arguments come last, and combined short options are split up. From man getopt:



    Output is generated for each element described in the previous section.
    Output is done in the same order as the elements are specified in the
    input, except for non-option parameters. Output can be done in
    compatible (unquoted) mode, or in such way that whitespace and other
    special characters within arguments and non-option parameters are
    preserved (see QUOTING). When the output is processed in the shell
    script, it will seem to be composed of distinct elements that can be
    processed one by one (by using the shift command in most shell
    languages).

    [...]

    Normally, no non-option parameters output is generated until all
    options and their arguments have been generated. Then '--' is
    generated as a single parameter, and after it the non-option parameters
    in the order they were found, each as a separate parameter.


    This effect is reflected in your code, where the option-handling loop assumes that all option arguments (including arguments to options) come first, and come separately, and are finally followed by non-option arguments.



    So, TEMP contains the rearranged, quoted, split-up options, and using eval set makes them script arguments.



    As for shift, it does what it always does: remove the first argument, and shift all arguments (so that what was $2 will now be $1). This eliminates the arguments that have been processed, so that, after this loop, only non-option arguments are left and you can conveniently use $@ without worrying about options.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Aug 4 '17 at 7:30









    muru

    34.6k579151




    34.6k579151











    • At least in the GNU enhanced getopt, you can prevent the re-ordering of the options list by setting the scanning mode to -. To do this, the first character in the short arguments list should be -, as in -o -ab:c::
      – bobpaul
      Mar 20 at 17:51
















    • At least in the GNU enhanced getopt, you can prevent the re-ordering of the options list by setting the scanning mode to -. To do this, the first character in the short arguments list should be -, as in -o -ab:c::
      – bobpaul
      Mar 20 at 17:51















    At least in the GNU enhanced getopt, you can prevent the re-ordering of the options list by setting the scanning mode to -. To do this, the first character in the short arguments list should be -, as in -o -ab:c::
    – bobpaul
    Mar 20 at 17:51




    At least in the GNU enhanced getopt, you can prevent the re-ordering of the options list by setting the scanning mode to -. To do this, the first character in the short arguments list should be -, as in -o -ab:c::
    – bobpaul
    Mar 20 at 17:51












    up vote
    1
    down vote













    The script works correctly when it gives you an error for -a 10. The -a option needs no parameter in this script. You should only use -a.



    The shift described in the man page as the following:



    shift [n]
    The positional parameters from n+1 ... are renamed to $1 .... Parameters represented by the numbers $# down to $#-n+1 are unset. n must be a non-negative number less than or equal to $#. If n is
    0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters are not changed. The return status is greater than zero if n is greater
    than $# or less than zero; otherwise 0.


    So basically it drops -a and shift the remaining arguments so the second parameter will be $1 in the next cycle.



    -- is also described in the man page:



     -- A -- signals the end of options and disables further option processing. Any arguments after the -- are treated as filenames and arguments. An argument of - is equivalent to --.





    share|improve this answer
























      up vote
      1
      down vote













      The script works correctly when it gives you an error for -a 10. The -a option needs no parameter in this script. You should only use -a.



      The shift described in the man page as the following:



      shift [n]
      The positional parameters from n+1 ... are renamed to $1 .... Parameters represented by the numbers $# down to $#-n+1 are unset. n must be a non-negative number less than or equal to $#. If n is
      0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters are not changed. The return status is greater than zero if n is greater
      than $# or less than zero; otherwise 0.


      So basically it drops -a and shift the remaining arguments so the second parameter will be $1 in the next cycle.



      -- is also described in the man page:



       -- A -- signals the end of options and disables further option processing. Any arguments after the -- are treated as filenames and arguments. An argument of - is equivalent to --.





      share|improve this answer






















        up vote
        1
        down vote










        up vote
        1
        down vote









        The script works correctly when it gives you an error for -a 10. The -a option needs no parameter in this script. You should only use -a.



        The shift described in the man page as the following:



        shift [n]
        The positional parameters from n+1 ... are renamed to $1 .... Parameters represented by the numbers $# down to $#-n+1 are unset. n must be a non-negative number less than or equal to $#. If n is
        0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters are not changed. The return status is greater than zero if n is greater
        than $# or less than zero; otherwise 0.


        So basically it drops -a and shift the remaining arguments so the second parameter will be $1 in the next cycle.



        -- is also described in the man page:



         -- A -- signals the end of options and disables further option processing. Any arguments after the -- are treated as filenames and arguments. An argument of - is equivalent to --.





        share|improve this answer












        The script works correctly when it gives you an error for -a 10. The -a option needs no parameter in this script. You should only use -a.



        The shift described in the man page as the following:



        shift [n]
        The positional parameters from n+1 ... are renamed to $1 .... Parameters represented by the numbers $# down to $#-n+1 are unset. n must be a non-negative number less than or equal to $#. If n is
        0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters are not changed. The return status is greater than zero if n is greater
        than $# or less than zero; otherwise 0.


        So basically it drops -a and shift the remaining arguments so the second parameter will be $1 in the next cycle.



        -- is also described in the man page:



         -- A -- signals the end of options and disables further option processing. Any arguments after the -- are treated as filenames and arguments. An argument of - is equivalent to --.






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Aug 4 '17 at 7:35









        asalamon74

        24122




        24122



























             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f383862%2fbash-why-is-used-eval-and-shift-in-a-script-that-parses-command-line-arguments%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            Bahrain

            Postfix configuration issue with fips on centos 7; mailgun relay