What is the difference between $* and $@?












57















Consider the following code:



foo () {
echo $*
}

bar () {
echo $@
}

foo 1 2 3 4
bar 1 2 3 4


It outputs:




1 2 3 4



1 2 3 4




I am using Ksh88, but I am interested in other common shells as well. If you happen to know any particularity for specific shells, please do mention them.



I found the follwing in the Ksh man page on Solaris:




The meaning of $* and $@ is
identical when not quoted or when used as a parameter
assignment value or as a file name. However, when used as a
command argument, $* is equivalent to ``$1d$2d...'', where d
is the first character of the IFS variable, whereas $@ is
equivalent to $1 $2 ....




I tried modifying the IFS variable, but it doesn't modify the output. Maybe I'm doing something wrong?










share|improve this question





























    57















    Consider the following code:



    foo () {
    echo $*
    }

    bar () {
    echo $@
    }

    foo 1 2 3 4
    bar 1 2 3 4


    It outputs:




    1 2 3 4



    1 2 3 4




    I am using Ksh88, but I am interested in other common shells as well. If you happen to know any particularity for specific shells, please do mention them.



    I found the follwing in the Ksh man page on Solaris:




    The meaning of $* and $@ is
    identical when not quoted or when used as a parameter
    assignment value or as a file name. However, when used as a
    command argument, $* is equivalent to ``$1d$2d...'', where d
    is the first character of the IFS variable, whereas $@ is
    equivalent to $1 $2 ....




    I tried modifying the IFS variable, but it doesn't modify the output. Maybe I'm doing something wrong?










    share|improve this question



























      57












      57








      57


      40






      Consider the following code:



      foo () {
      echo $*
      }

      bar () {
      echo $@
      }

      foo 1 2 3 4
      bar 1 2 3 4


      It outputs:




      1 2 3 4



      1 2 3 4




      I am using Ksh88, but I am interested in other common shells as well. If you happen to know any particularity for specific shells, please do mention them.



      I found the follwing in the Ksh man page on Solaris:




      The meaning of $* and $@ is
      identical when not quoted or when used as a parameter
      assignment value or as a file name. However, when used as a
      command argument, $* is equivalent to ``$1d$2d...'', where d
      is the first character of the IFS variable, whereas $@ is
      equivalent to $1 $2 ....




      I tried modifying the IFS variable, but it doesn't modify the output. Maybe I'm doing something wrong?










      share|improve this question
















      Consider the following code:



      foo () {
      echo $*
      }

      bar () {
      echo $@
      }

      foo 1 2 3 4
      bar 1 2 3 4


      It outputs:




      1 2 3 4



      1 2 3 4




      I am using Ksh88, but I am interested in other common shells as well. If you happen to know any particularity for specific shells, please do mention them.



      I found the follwing in the Ksh man page on Solaris:




      The meaning of $* and $@ is
      identical when not quoted or when used as a parameter
      assignment value or as a file name. However, when used as a
      command argument, $* is equivalent to ``$1d$2d...'', where d
      is the first character of the IFS variable, whereas $@ is
      equivalent to $1 $2 ....




      I tried modifying the IFS variable, but it doesn't modify the output. Maybe I'm doing something wrong?







      shell quoting ksh arguments






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited May 24 '14 at 2:07









      Gilles

      543k12811001617




      543k12811001617










      asked Jun 25 '12 at 9:51









      rahmurahmu

      10.5k2070112




      10.5k2070112






















          8 Answers
          8






          active

          oldest

          votes


















          73














          When they are not quoted, $* and $@ are the same. You shouldn't use either of these, because they can break unexpectedly as soon as you have arguments containing spaces or wildcards.





          "$*" expands to a single word "$1c$2c...". Usually c is a space, but it's actually the first character of IFS, so it can be anything you choose.



          The only good use I've ever found for it is:



          join arguments with comma (simple version)



          join1() {
          typeset IFS=,
          echo "$*"
          }

          join1 a b c # => a,b,c


          join arguments with the specified delimiter (better version)



          join2() {
          typeset IFS=$1 # typeset makes a local variable in ksh (see footnote)
          shift
          echo "$*"
          }

          join2 + a b c # => a+b+c




          "$@" expands to separate words: "$1" "$2" ...



          This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*).





          Let's write a script called svim that runs vim with sudo. We'll do three versions to illustrate the difference.



          svim1



          #!/bin/sh
          sudo vim $*


          svim2



          #!/bin/sh
          sudo vim "$*"


          svim3



          #!/bin/sh
          sudo vim "$@"


          All of them will be fine for simple cases, e.g. a single file name that doesn't contain spaces:



          svim1 foo.txt             # == sudo vim foo.txt
          svim2 foo.txt # == sudo vim "foo.txt"
          svim2 foo.txt # == sudo vim "foo.txt"


          But only $* and "$@" work properly if you have multiple arguments.



          svim1 foo.txt bar.txt     # == sudo vim foo.txt bar.txt
          svim2 foo.txt bar.txt # == sudo vim "foo.txt bar.txt" # one file name!
          svim3 foo.txt bar.txt # == sudo vim "foo.txt" "bar.txt"


          And only "$*" and "$@" work properly if you have arguments containing spaces.



          svim1 "shopping list.txt" # == sudo vim shopping list.txt   # two file names!
          svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
          svim3 "shopping list.txt" # == sudo vim "shopping list.txt"


          So only "$@" will work properly all the time.





          typeset is how to make a local variable in ksh (bash and ash use local instead). It means IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work properly if IFS is set to something non-standard.






          share|improve this answer





















          • 1





            Wonderful explanation, thank you very much.

            – rahmu
            Jun 26 '12 at 15:29











          • Thank you for an example of using $*. I was always considering it to be completely useless... join with delimiter is a good use case.

            – anishsane
            Mar 31 '16 at 5:01



















          33














          Short answer: use "$@" (note the double quotes). The other forms are very rarely useful.



          "$@" is a rather strange syntax. It is replaced by all the positional parameters, as separate fields. If there are no positional parameters ($# is 0), then "$@" expands to nothing (not an empty string, but a list with 0 elements), if there is one positional parameter then "$@" is equivalent to "$1", if there are two positional parameters then "$@" is equivalent to "$1" "$2", etc.



          "$@" allows you to pass down the arguments of a script or function to another command. It is very useful for wrappers that do things like setting environment variables, preparing data files, etc. before calling a command with the same arguments and options that the wrapper was called with.



          For example, the following function filters the output of cvs -nq update. Apart from the output filtering and the return status (which is that of grep rather than that of cvs), calling cvssm on some arguments behaves like calling cvs -nq update with these arguments.



          cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }


          "$@" expands to the list of positional parameters. In shells that support arrays, there is a similar syntax to expand to the list of elements of the array: "${array[@]}" (the braces are mandatory except in zsh). Again, the double quotes are somewhat misleading: they protect against field splitting and pattern generation of the array elements, but each array element ends up in its own field.




          Some ancient shells had what is arguably a bug: when there were no positional arguments, "$@" expanded to a single field containing an empty string, rather than into no field. This led to the workaround ${1+"$@"} (made famous via the Perl documentation). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. /bin/sh is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there /usr/xpg4/bin/sh is safe so only #!/bin/sh script are affected, not #!/usr/bin/env sh scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.





          "$*" always expands to one word. This word contains the positional parameters, concatenated with a space in between. (More generally, the separator is the first character of the value of the IFS variable. If the value of IFS is the empty string, the separator is the empty string.) If there are no positional parameters then "$*" is the empty string, if there are two positional parameters and IFS has its default value then "$*" is equivalent to "$1 $2", etc.



          $@ and $* outside quotes are equivalent. They expand to the list of positional parameters, as separate fields, like "$@"; but each resulting field is then split into separate fields which are treated as file name wildcard patterns, as usual with unquoted variable expansions.



          For example, if the current directory contains three files bar, baz and foo, then:



          set --         # no positional parameters
          for x in "$@"; do echo "$x"; done # prints nothing
          for x in "$*"; do echo "$x"; done # prints 1 empty line
          for x in $*; do echo "$x"; done # prints nothing
          set -- "b* c*" "qux"
          echo "$@" # prints `b* c* qux`
          echo "$*" # prints `b* c* qux`
          echo $* # prints `bar baz c* qux`
          for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
          for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
          for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`





          share|improve this answer





















          • 1





            Historical note: on some ancient Bourne shells, "$@" did indeed expand to a list consisiting of the empty string: unix.stackexchange.com/questions/68484/…

            – ninjalj
            Oct 9 '13 at 13:01



















          24














          Here is a simple script to demonstrates the difference between $* and $@:



          #!/bin/bash

          test_param() {
          echo "Receive $# parameters"
          echo Using '$*'

          echo
          for param in $*; do
          printf '==>%s<==n' "$param"
          done;

          echo
          echo Using '"$*"'
          for param in "$*"; do
          printf '==>%s<==n' "$param"
          done;

          echo
          echo Using '$@'
          for param in $@; do
          printf '==>%s<==n' "$param"
          done;

          echo
          echo Using '"$@"';
          for param in "$@"; do
          printf '==>%s<==n' "$param"
          done
          }

          IFS="^${IFS}"

          test_param 1 2 3 "a b c"


          Output:



          % cuonglm at ~
          % bash test.sh
          Receive 4 parameters

          Using $*
          ==>1<==
          ==>2<==
          ==>3<==
          ==>a<==
          ==>b<==
          ==>c<==

          Using "$*"
          ==>1^2^3^a b c<==

          Using $@
          ==>1<==
          ==>2<==
          ==>3<==
          ==>a<==
          ==>b<==
          ==>c<==

          Using "$@"
          ==>1<==
          ==>2<==
          ==>3<==
          ==>a b c<==


          In array syntax, there is no difference when using $* or $@. It only make sense when you use them with double quotes "$*" and "$@".






          share|improve this answer


























          • Excellent example! Can you explain the use of IFS="^${IFS}", though?

            – Russ
            Sep 16 '16 at 12:47











          • @Russ: It show you how value is concat with the first character in IFS.

            – cuonglm
            Sep 16 '16 at 13:03











          • In the same way that IFS="^xxxxx" would do? The trailing ${IFS} suffix made me think you were doing something trickier, like somehow automatically recovering the original IFS at the end (eg: first char automatically shifted out or something).

            – Russ
            Sep 16 '16 at 14:48





















          11














          The code you provided will give the same result. To understand it better, try this:



          foo () {
          for i in "$*"; do
          echo "$i"
          done
          }

          bar () {
          for i in "$@"; do
          echo "$i"
          done
          }


          The output should now be different. Here's what I get:



          $ foo() 1 2 3 4
          1 2 3 4
          $ bar() 1 2 3 4
          1
          2
          3
          4


          This worked for me on bash. As far as I know, ksh should not differ much. Essentially, quoting $* will treat everything as one word, and quoting $@ will treat the list as separate words, as can be seen in the example above.



          As an example of using the IFS variable with $*, consider this



          fooifs () {
          IFS="c"
          for i in "$*"; do
          echo "$i"
          done
          unset IFS # reset to the original value
          }


          I get this as a result:



          $ fooifs 1 2 3 4
          1c2c3c4


          Also, I've just confirmed it works the same in ksh. Both bash and ksh tested here were under OSX but I can't see how that would matter much.






          share|improve this answer


























          • "changed within a function - doesn't affect the global". Did you test that?

            – Mikel
            Jun 25 '12 at 15:11











          • Yes, I've checked that. For the peace of mind, I'll add the unset IFS at the end to reset it to the original, but it worked for me no problem and doing an echo $IFS resulted in the standard output I get from it. Setting the IFS withing the curly brackets introduces a new scope, so unless you export it, it will not affect the outside IFS.

            – Wojtek Rzepala
            Jun 25 '12 at 16:00













          • echo $IFS doesn't prove anything, because the shell sees the ,, but then does word splitting using IFS! Try echo "$IFS".

            – Mikel
            Jun 25 '12 at 16:43











          • good point. unsetting IFS should solve that.

            – Wojtek Rzepala
            Jun 25 '12 at 17:39











          • Unless IFS had a different custom value before calling the function. But yes, most of the time unsetting IFS will work.

            – Mikel
            Jun 25 '12 at 20:51



















          6














          The difference is important when writing scripts that should use the positional parameters in the right way...



          Imagine the following call:



          $ myuseradd -m -c "Carlos Campderrós" ccampderros


          Here there are just 4 parameters:



          $1 => -m
          $2 => -c
          $3 => Carlos Campderrós
          $4 => ccampderros


          In my case, myuseradd is just a wrapper for useradd that accepts the same parameters, but adds a quota for the user:



          #!/bin/bash -e

          useradd "$@"
          setquota -u "${!#}" 10000 11000 1000 1100


          Notice the call to useradd "$@", with $@ quoted. This will respect the parameters and send them as-they-are to useradd. If you were to unquote $@ (or to use $* also unquoted), useradd would see 5 parameters, as the 3rd parameter which contained a space would be split in two:



          $1 => -m
          $2 => -c
          $3 => Carlos
          $4 => Campderrós
          $5 => ccampderros


          (and conversely, if you were to use "$*", useradd would only see one parameter: -m -c Carlos Campderrós ccampderros)



          So, in short, if you need to work with parameters respecting multi-word parameters, use "$@".






          share|improve this answer































            4














               *      Expands  to  the positional parameters, starting from one.  When
            the expansion occurs within double quotes, it expands to a sin‐
            gle word with the value of each parameter separated by the first
            character of the IFS special variable. That is, "$*" is equiva‐
            lent to "$1c$2c...", where c is the first character of the value
            of the IFS variable. If IFS is unset, the parameters are sepa‐
            rated by spaces. If IFS is null, the parameters are joined
            without intervening separators.
            @ Expands to the positional parameters, starting from one. When
            the expansion occurs within double quotes, each parameter
            expands to a separate word. That is, "$@" is equivalent to "$1"
            "$2" ... If the double-quoted expansion occurs within a word,
            the expansion of the first parameter is joined with the begin‐
            ning part of the original word, and the expansion of the last
            parameter is joined with the last part of the original word.
            When there are no positional parameters, "$@" and $@ expand to
            nothing (i.e., they are removed).


            // man bash . is ksh, afair, similar behaviour.






            share|improve this answer































              2














              Talking about differences between zsh and bash:



              With quotes around $@ and $*, zsh and bash behave the same, and I guess the result is quite standard among all shells:



               $ f () { for i in "$@"; do echo +"$i"+; done; }; f 'a a' 'b' ''
              +a a+
              +b+
              ++
              $ f () { for i in "$*"; do echo +"$i"+; done; }; f 'a a' 'b' ''
              +a a b +


              Without quotes, results are the same for $* and $@, but different in bash and in zsh. In this case zsh shows some odd behaviour:



              bash$ f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
              +a+
              +a+
              +b+
              zsh% f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
              +a a+
              +b+


              (Zsh usually don't split textual data using IFS, unless explicitly requested, but notice that here the empty argument is unexpectedly missing in the list.)






              share|improve this answer





















              • 1





                In zsh, $@ isn't special in this respect: $x expands to at most one word, but empty variables expand to nothing (not an empty word). Try print -l a $foo b with foo empty or undefined.

                – Gilles
                Jun 25 '12 at 23:27



















              0














              One of the answers says $* (which I think of as a "splat") is rarely useful.



              I search google with G() { IFS='+' ; w3m "https://encrypted.google.com/search?q=$*" ; }



              Since URL’s are often split with a +, but my keyboard makes   easier to reach than +, $* + $IFS feel worthwhile.






              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',
                autoActivateHeartbeat: false,
                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%2f41571%2fwhat-is-the-difference-between-and%23new-answer', 'question_page');
                }
                );

                Post as a guest















                Required, but never shown

























                8 Answers
                8






                active

                oldest

                votes








                8 Answers
                8






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes









                73














                When they are not quoted, $* and $@ are the same. You shouldn't use either of these, because they can break unexpectedly as soon as you have arguments containing spaces or wildcards.





                "$*" expands to a single word "$1c$2c...". Usually c is a space, but it's actually the first character of IFS, so it can be anything you choose.



                The only good use I've ever found for it is:



                join arguments with comma (simple version)



                join1() {
                typeset IFS=,
                echo "$*"
                }

                join1 a b c # => a,b,c


                join arguments with the specified delimiter (better version)



                join2() {
                typeset IFS=$1 # typeset makes a local variable in ksh (see footnote)
                shift
                echo "$*"
                }

                join2 + a b c # => a+b+c




                "$@" expands to separate words: "$1" "$2" ...



                This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*).





                Let's write a script called svim that runs vim with sudo. We'll do three versions to illustrate the difference.



                svim1



                #!/bin/sh
                sudo vim $*


                svim2



                #!/bin/sh
                sudo vim "$*"


                svim3



                #!/bin/sh
                sudo vim "$@"


                All of them will be fine for simple cases, e.g. a single file name that doesn't contain spaces:



                svim1 foo.txt             # == sudo vim foo.txt
                svim2 foo.txt # == sudo vim "foo.txt"
                svim2 foo.txt # == sudo vim "foo.txt"


                But only $* and "$@" work properly if you have multiple arguments.



                svim1 foo.txt bar.txt     # == sudo vim foo.txt bar.txt
                svim2 foo.txt bar.txt # == sudo vim "foo.txt bar.txt" # one file name!
                svim3 foo.txt bar.txt # == sudo vim "foo.txt" "bar.txt"


                And only "$*" and "$@" work properly if you have arguments containing spaces.



                svim1 "shopping list.txt" # == sudo vim shopping list.txt   # two file names!
                svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
                svim3 "shopping list.txt" # == sudo vim "shopping list.txt"


                So only "$@" will work properly all the time.





                typeset is how to make a local variable in ksh (bash and ash use local instead). It means IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work properly if IFS is set to something non-standard.






                share|improve this answer





















                • 1





                  Wonderful explanation, thank you very much.

                  – rahmu
                  Jun 26 '12 at 15:29











                • Thank you for an example of using $*. I was always considering it to be completely useless... join with delimiter is a good use case.

                  – anishsane
                  Mar 31 '16 at 5:01
















                73














                When they are not quoted, $* and $@ are the same. You shouldn't use either of these, because they can break unexpectedly as soon as you have arguments containing spaces or wildcards.





                "$*" expands to a single word "$1c$2c...". Usually c is a space, but it's actually the first character of IFS, so it can be anything you choose.



                The only good use I've ever found for it is:



                join arguments with comma (simple version)



                join1() {
                typeset IFS=,
                echo "$*"
                }

                join1 a b c # => a,b,c


                join arguments with the specified delimiter (better version)



                join2() {
                typeset IFS=$1 # typeset makes a local variable in ksh (see footnote)
                shift
                echo "$*"
                }

                join2 + a b c # => a+b+c




                "$@" expands to separate words: "$1" "$2" ...



                This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*).





                Let's write a script called svim that runs vim with sudo. We'll do three versions to illustrate the difference.



                svim1



                #!/bin/sh
                sudo vim $*


                svim2



                #!/bin/sh
                sudo vim "$*"


                svim3



                #!/bin/sh
                sudo vim "$@"


                All of them will be fine for simple cases, e.g. a single file name that doesn't contain spaces:



                svim1 foo.txt             # == sudo vim foo.txt
                svim2 foo.txt # == sudo vim "foo.txt"
                svim2 foo.txt # == sudo vim "foo.txt"


                But only $* and "$@" work properly if you have multiple arguments.



                svim1 foo.txt bar.txt     # == sudo vim foo.txt bar.txt
                svim2 foo.txt bar.txt # == sudo vim "foo.txt bar.txt" # one file name!
                svim3 foo.txt bar.txt # == sudo vim "foo.txt" "bar.txt"


                And only "$*" and "$@" work properly if you have arguments containing spaces.



                svim1 "shopping list.txt" # == sudo vim shopping list.txt   # two file names!
                svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
                svim3 "shopping list.txt" # == sudo vim "shopping list.txt"


                So only "$@" will work properly all the time.





                typeset is how to make a local variable in ksh (bash and ash use local instead). It means IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work properly if IFS is set to something non-standard.






                share|improve this answer





















                • 1





                  Wonderful explanation, thank you very much.

                  – rahmu
                  Jun 26 '12 at 15:29











                • Thank you for an example of using $*. I was always considering it to be completely useless... join with delimiter is a good use case.

                  – anishsane
                  Mar 31 '16 at 5:01














                73












                73








                73







                When they are not quoted, $* and $@ are the same. You shouldn't use either of these, because they can break unexpectedly as soon as you have arguments containing spaces or wildcards.





                "$*" expands to a single word "$1c$2c...". Usually c is a space, but it's actually the first character of IFS, so it can be anything you choose.



                The only good use I've ever found for it is:



                join arguments with comma (simple version)



                join1() {
                typeset IFS=,
                echo "$*"
                }

                join1 a b c # => a,b,c


                join arguments with the specified delimiter (better version)



                join2() {
                typeset IFS=$1 # typeset makes a local variable in ksh (see footnote)
                shift
                echo "$*"
                }

                join2 + a b c # => a+b+c




                "$@" expands to separate words: "$1" "$2" ...



                This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*).





                Let's write a script called svim that runs vim with sudo. We'll do three versions to illustrate the difference.



                svim1



                #!/bin/sh
                sudo vim $*


                svim2



                #!/bin/sh
                sudo vim "$*"


                svim3



                #!/bin/sh
                sudo vim "$@"


                All of them will be fine for simple cases, e.g. a single file name that doesn't contain spaces:



                svim1 foo.txt             # == sudo vim foo.txt
                svim2 foo.txt # == sudo vim "foo.txt"
                svim2 foo.txt # == sudo vim "foo.txt"


                But only $* and "$@" work properly if you have multiple arguments.



                svim1 foo.txt bar.txt     # == sudo vim foo.txt bar.txt
                svim2 foo.txt bar.txt # == sudo vim "foo.txt bar.txt" # one file name!
                svim3 foo.txt bar.txt # == sudo vim "foo.txt" "bar.txt"


                And only "$*" and "$@" work properly if you have arguments containing spaces.



                svim1 "shopping list.txt" # == sudo vim shopping list.txt   # two file names!
                svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
                svim3 "shopping list.txt" # == sudo vim "shopping list.txt"


                So only "$@" will work properly all the time.





                typeset is how to make a local variable in ksh (bash and ash use local instead). It means IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work properly if IFS is set to something non-standard.






                share|improve this answer















                When they are not quoted, $* and $@ are the same. You shouldn't use either of these, because they can break unexpectedly as soon as you have arguments containing spaces or wildcards.





                "$*" expands to a single word "$1c$2c...". Usually c is a space, but it's actually the first character of IFS, so it can be anything you choose.



                The only good use I've ever found for it is:



                join arguments with comma (simple version)



                join1() {
                typeset IFS=,
                echo "$*"
                }

                join1 a b c # => a,b,c


                join arguments with the specified delimiter (better version)



                join2() {
                typeset IFS=$1 # typeset makes a local variable in ksh (see footnote)
                shift
                echo "$*"
                }

                join2 + a b c # => a+b+c




                "$@" expands to separate words: "$1" "$2" ...



                This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1" contains a space or an asterisk (*).





                Let's write a script called svim that runs vim with sudo. We'll do three versions to illustrate the difference.



                svim1



                #!/bin/sh
                sudo vim $*


                svim2



                #!/bin/sh
                sudo vim "$*"


                svim3



                #!/bin/sh
                sudo vim "$@"


                All of them will be fine for simple cases, e.g. a single file name that doesn't contain spaces:



                svim1 foo.txt             # == sudo vim foo.txt
                svim2 foo.txt # == sudo vim "foo.txt"
                svim2 foo.txt # == sudo vim "foo.txt"


                But only $* and "$@" work properly if you have multiple arguments.



                svim1 foo.txt bar.txt     # == sudo vim foo.txt bar.txt
                svim2 foo.txt bar.txt # == sudo vim "foo.txt bar.txt" # one file name!
                svim3 foo.txt bar.txt # == sudo vim "foo.txt" "bar.txt"


                And only "$*" and "$@" work properly if you have arguments containing spaces.



                svim1 "shopping list.txt" # == sudo vim shopping list.txt   # two file names!
                svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
                svim3 "shopping list.txt" # == sudo vim "shopping list.txt"


                So only "$@" will work properly all the time.





                typeset is how to make a local variable in ksh (bash and ash use local instead). It means IFS will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work properly if IFS is set to something non-standard.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Feb 27 at 16:10









                glenn jackman

                52.4k573113




                52.4k573113










                answered Jun 25 '12 at 15:25









                MikelMikel

                39.9k10103127




                39.9k10103127








                • 1





                  Wonderful explanation, thank you very much.

                  – rahmu
                  Jun 26 '12 at 15:29











                • Thank you for an example of using $*. I was always considering it to be completely useless... join with delimiter is a good use case.

                  – anishsane
                  Mar 31 '16 at 5:01














                • 1





                  Wonderful explanation, thank you very much.

                  – rahmu
                  Jun 26 '12 at 15:29











                • Thank you for an example of using $*. I was always considering it to be completely useless... join with delimiter is a good use case.

                  – anishsane
                  Mar 31 '16 at 5:01








                1




                1





                Wonderful explanation, thank you very much.

                – rahmu
                Jun 26 '12 at 15:29





                Wonderful explanation, thank you very much.

                – rahmu
                Jun 26 '12 at 15:29













                Thank you for an example of using $*. I was always considering it to be completely useless... join with delimiter is a good use case.

                – anishsane
                Mar 31 '16 at 5:01





                Thank you for an example of using $*. I was always considering it to be completely useless... join with delimiter is a good use case.

                – anishsane
                Mar 31 '16 at 5:01













                33














                Short answer: use "$@" (note the double quotes). The other forms are very rarely useful.



                "$@" is a rather strange syntax. It is replaced by all the positional parameters, as separate fields. If there are no positional parameters ($# is 0), then "$@" expands to nothing (not an empty string, but a list with 0 elements), if there is one positional parameter then "$@" is equivalent to "$1", if there are two positional parameters then "$@" is equivalent to "$1" "$2", etc.



                "$@" allows you to pass down the arguments of a script or function to another command. It is very useful for wrappers that do things like setting environment variables, preparing data files, etc. before calling a command with the same arguments and options that the wrapper was called with.



                For example, the following function filters the output of cvs -nq update. Apart from the output filtering and the return status (which is that of grep rather than that of cvs), calling cvssm on some arguments behaves like calling cvs -nq update with these arguments.



                cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }


                "$@" expands to the list of positional parameters. In shells that support arrays, there is a similar syntax to expand to the list of elements of the array: "${array[@]}" (the braces are mandatory except in zsh). Again, the double quotes are somewhat misleading: they protect against field splitting and pattern generation of the array elements, but each array element ends up in its own field.




                Some ancient shells had what is arguably a bug: when there were no positional arguments, "$@" expanded to a single field containing an empty string, rather than into no field. This led to the workaround ${1+"$@"} (made famous via the Perl documentation). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. /bin/sh is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there /usr/xpg4/bin/sh is safe so only #!/bin/sh script are affected, not #!/usr/bin/env sh scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.





                "$*" always expands to one word. This word contains the positional parameters, concatenated with a space in between. (More generally, the separator is the first character of the value of the IFS variable. If the value of IFS is the empty string, the separator is the empty string.) If there are no positional parameters then "$*" is the empty string, if there are two positional parameters and IFS has its default value then "$*" is equivalent to "$1 $2", etc.



                $@ and $* outside quotes are equivalent. They expand to the list of positional parameters, as separate fields, like "$@"; but each resulting field is then split into separate fields which are treated as file name wildcard patterns, as usual with unquoted variable expansions.



                For example, if the current directory contains three files bar, baz and foo, then:



                set --         # no positional parameters
                for x in "$@"; do echo "$x"; done # prints nothing
                for x in "$*"; do echo "$x"; done # prints 1 empty line
                for x in $*; do echo "$x"; done # prints nothing
                set -- "b* c*" "qux"
                echo "$@" # prints `b* c* qux`
                echo "$*" # prints `b* c* qux`
                echo $* # prints `bar baz c* qux`
                for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
                for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
                for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`





                share|improve this answer





















                • 1





                  Historical note: on some ancient Bourne shells, "$@" did indeed expand to a list consisiting of the empty string: unix.stackexchange.com/questions/68484/…

                  – ninjalj
                  Oct 9 '13 at 13:01
















                33














                Short answer: use "$@" (note the double quotes). The other forms are very rarely useful.



                "$@" is a rather strange syntax. It is replaced by all the positional parameters, as separate fields. If there are no positional parameters ($# is 0), then "$@" expands to nothing (not an empty string, but a list with 0 elements), if there is one positional parameter then "$@" is equivalent to "$1", if there are two positional parameters then "$@" is equivalent to "$1" "$2", etc.



                "$@" allows you to pass down the arguments of a script or function to another command. It is very useful for wrappers that do things like setting environment variables, preparing data files, etc. before calling a command with the same arguments and options that the wrapper was called with.



                For example, the following function filters the output of cvs -nq update. Apart from the output filtering and the return status (which is that of grep rather than that of cvs), calling cvssm on some arguments behaves like calling cvs -nq update with these arguments.



                cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }


                "$@" expands to the list of positional parameters. In shells that support arrays, there is a similar syntax to expand to the list of elements of the array: "${array[@]}" (the braces are mandatory except in zsh). Again, the double quotes are somewhat misleading: they protect against field splitting and pattern generation of the array elements, but each array element ends up in its own field.




                Some ancient shells had what is arguably a bug: when there were no positional arguments, "$@" expanded to a single field containing an empty string, rather than into no field. This led to the workaround ${1+"$@"} (made famous via the Perl documentation). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. /bin/sh is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there /usr/xpg4/bin/sh is safe so only #!/bin/sh script are affected, not #!/usr/bin/env sh scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.





                "$*" always expands to one word. This word contains the positional parameters, concatenated with a space in between. (More generally, the separator is the first character of the value of the IFS variable. If the value of IFS is the empty string, the separator is the empty string.) If there are no positional parameters then "$*" is the empty string, if there are two positional parameters and IFS has its default value then "$*" is equivalent to "$1 $2", etc.



                $@ and $* outside quotes are equivalent. They expand to the list of positional parameters, as separate fields, like "$@"; but each resulting field is then split into separate fields which are treated as file name wildcard patterns, as usual with unquoted variable expansions.



                For example, if the current directory contains three files bar, baz and foo, then:



                set --         # no positional parameters
                for x in "$@"; do echo "$x"; done # prints nothing
                for x in "$*"; do echo "$x"; done # prints 1 empty line
                for x in $*; do echo "$x"; done # prints nothing
                set -- "b* c*" "qux"
                echo "$@" # prints `b* c* qux`
                echo "$*" # prints `b* c* qux`
                echo $* # prints `bar baz c* qux`
                for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
                for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
                for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`





                share|improve this answer





















                • 1





                  Historical note: on some ancient Bourne shells, "$@" did indeed expand to a list consisiting of the empty string: unix.stackexchange.com/questions/68484/…

                  – ninjalj
                  Oct 9 '13 at 13:01














                33












                33








                33







                Short answer: use "$@" (note the double quotes). The other forms are very rarely useful.



                "$@" is a rather strange syntax. It is replaced by all the positional parameters, as separate fields. If there are no positional parameters ($# is 0), then "$@" expands to nothing (not an empty string, but a list with 0 elements), if there is one positional parameter then "$@" is equivalent to "$1", if there are two positional parameters then "$@" is equivalent to "$1" "$2", etc.



                "$@" allows you to pass down the arguments of a script or function to another command. It is very useful for wrappers that do things like setting environment variables, preparing data files, etc. before calling a command with the same arguments and options that the wrapper was called with.



                For example, the following function filters the output of cvs -nq update. Apart from the output filtering and the return status (which is that of grep rather than that of cvs), calling cvssm on some arguments behaves like calling cvs -nq update with these arguments.



                cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }


                "$@" expands to the list of positional parameters. In shells that support arrays, there is a similar syntax to expand to the list of elements of the array: "${array[@]}" (the braces are mandatory except in zsh). Again, the double quotes are somewhat misleading: they protect against field splitting and pattern generation of the array elements, but each array element ends up in its own field.




                Some ancient shells had what is arguably a bug: when there were no positional arguments, "$@" expanded to a single field containing an empty string, rather than into no field. This led to the workaround ${1+"$@"} (made famous via the Perl documentation). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. /bin/sh is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there /usr/xpg4/bin/sh is safe so only #!/bin/sh script are affected, not #!/usr/bin/env sh scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.





                "$*" always expands to one word. This word contains the positional parameters, concatenated with a space in between. (More generally, the separator is the first character of the value of the IFS variable. If the value of IFS is the empty string, the separator is the empty string.) If there are no positional parameters then "$*" is the empty string, if there are two positional parameters and IFS has its default value then "$*" is equivalent to "$1 $2", etc.



                $@ and $* outside quotes are equivalent. They expand to the list of positional parameters, as separate fields, like "$@"; but each resulting field is then split into separate fields which are treated as file name wildcard patterns, as usual with unquoted variable expansions.



                For example, if the current directory contains three files bar, baz and foo, then:



                set --         # no positional parameters
                for x in "$@"; do echo "$x"; done # prints nothing
                for x in "$*"; do echo "$x"; done # prints 1 empty line
                for x in $*; do echo "$x"; done # prints nothing
                set -- "b* c*" "qux"
                echo "$@" # prints `b* c* qux`
                echo "$*" # prints `b* c* qux`
                echo $* # prints `bar baz c* qux`
                for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
                for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
                for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`





                share|improve this answer















                Short answer: use "$@" (note the double quotes). The other forms are very rarely useful.



                "$@" is a rather strange syntax. It is replaced by all the positional parameters, as separate fields. If there are no positional parameters ($# is 0), then "$@" expands to nothing (not an empty string, but a list with 0 elements), if there is one positional parameter then "$@" is equivalent to "$1", if there are two positional parameters then "$@" is equivalent to "$1" "$2", etc.



                "$@" allows you to pass down the arguments of a script or function to another command. It is very useful for wrappers that do things like setting environment variables, preparing data files, etc. before calling a command with the same arguments and options that the wrapper was called with.



                For example, the following function filters the output of cvs -nq update. Apart from the output filtering and the return status (which is that of grep rather than that of cvs), calling cvssm on some arguments behaves like calling cvs -nq update with these arguments.



                cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }


                "$@" expands to the list of positional parameters. In shells that support arrays, there is a similar syntax to expand to the list of elements of the array: "${array[@]}" (the braces are mandatory except in zsh). Again, the double quotes are somewhat misleading: they protect against field splitting and pattern generation of the array elements, but each array element ends up in its own field.




                Some ancient shells had what is arguably a bug: when there were no positional arguments, "$@" expanded to a single field containing an empty string, rather than into no field. This led to the workaround ${1+"$@"} (made famous via the Perl documentation). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. /bin/sh is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there /usr/xpg4/bin/sh is safe so only #!/bin/sh script are affected, not #!/usr/bin/env sh scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.





                "$*" always expands to one word. This word contains the positional parameters, concatenated with a space in between. (More generally, the separator is the first character of the value of the IFS variable. If the value of IFS is the empty string, the separator is the empty string.) If there are no positional parameters then "$*" is the empty string, if there are two positional parameters and IFS has its default value then "$*" is equivalent to "$1 $2", etc.



                $@ and $* outside quotes are equivalent. They expand to the list of positional parameters, as separate fields, like "$@"; but each resulting field is then split into separate fields which are treated as file name wildcard patterns, as usual with unquoted variable expansions.



                For example, if the current directory contains three files bar, baz and foo, then:



                set --         # no positional parameters
                for x in "$@"; do echo "$x"; done # prints nothing
                for x in "$*"; do echo "$x"; done # prints 1 empty line
                for x in $*; do echo "$x"; done # prints nothing
                set -- "b* c*" "qux"
                echo "$@" # prints `b* c* qux`
                echo "$*" # prints `b* c* qux`
                echo $* # prints `bar baz c* qux`
                for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
                for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
                for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Apr 13 '17 at 12:36









                Community

                1




                1










                answered Oct 9 '13 at 1:20









                GillesGilles

                543k12811001617




                543k12811001617








                • 1





                  Historical note: on some ancient Bourne shells, "$@" did indeed expand to a list consisiting of the empty string: unix.stackexchange.com/questions/68484/…

                  – ninjalj
                  Oct 9 '13 at 13:01














                • 1





                  Historical note: on some ancient Bourne shells, "$@" did indeed expand to a list consisiting of the empty string: unix.stackexchange.com/questions/68484/…

                  – ninjalj
                  Oct 9 '13 at 13:01








                1




                1





                Historical note: on some ancient Bourne shells, "$@" did indeed expand to a list consisiting of the empty string: unix.stackexchange.com/questions/68484/…

                – ninjalj
                Oct 9 '13 at 13:01





                Historical note: on some ancient Bourne shells, "$@" did indeed expand to a list consisiting of the empty string: unix.stackexchange.com/questions/68484/…

                – ninjalj
                Oct 9 '13 at 13:01











                24














                Here is a simple script to demonstrates the difference between $* and $@:



                #!/bin/bash

                test_param() {
                echo "Receive $# parameters"
                echo Using '$*'

                echo
                for param in $*; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '"$*"'
                for param in "$*"; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '$@'
                for param in $@; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '"$@"';
                for param in "$@"; do
                printf '==>%s<==n' "$param"
                done
                }

                IFS="^${IFS}"

                test_param 1 2 3 "a b c"


                Output:



                % cuonglm at ~
                % bash test.sh
                Receive 4 parameters

                Using $*
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a<==
                ==>b<==
                ==>c<==

                Using "$*"
                ==>1^2^3^a b c<==

                Using $@
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a<==
                ==>b<==
                ==>c<==

                Using "$@"
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a b c<==


                In array syntax, there is no difference when using $* or $@. It only make sense when you use them with double quotes "$*" and "$@".






                share|improve this answer


























                • Excellent example! Can you explain the use of IFS="^${IFS}", though?

                  – Russ
                  Sep 16 '16 at 12:47











                • @Russ: It show you how value is concat with the first character in IFS.

                  – cuonglm
                  Sep 16 '16 at 13:03











                • In the same way that IFS="^xxxxx" would do? The trailing ${IFS} suffix made me think you were doing something trickier, like somehow automatically recovering the original IFS at the end (eg: first char automatically shifted out or something).

                  – Russ
                  Sep 16 '16 at 14:48


















                24














                Here is a simple script to demonstrates the difference between $* and $@:



                #!/bin/bash

                test_param() {
                echo "Receive $# parameters"
                echo Using '$*'

                echo
                for param in $*; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '"$*"'
                for param in "$*"; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '$@'
                for param in $@; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '"$@"';
                for param in "$@"; do
                printf '==>%s<==n' "$param"
                done
                }

                IFS="^${IFS}"

                test_param 1 2 3 "a b c"


                Output:



                % cuonglm at ~
                % bash test.sh
                Receive 4 parameters

                Using $*
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a<==
                ==>b<==
                ==>c<==

                Using "$*"
                ==>1^2^3^a b c<==

                Using $@
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a<==
                ==>b<==
                ==>c<==

                Using "$@"
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a b c<==


                In array syntax, there is no difference when using $* or $@. It only make sense when you use them with double quotes "$*" and "$@".






                share|improve this answer


























                • Excellent example! Can you explain the use of IFS="^${IFS}", though?

                  – Russ
                  Sep 16 '16 at 12:47











                • @Russ: It show you how value is concat with the first character in IFS.

                  – cuonglm
                  Sep 16 '16 at 13:03











                • In the same way that IFS="^xxxxx" would do? The trailing ${IFS} suffix made me think you were doing something trickier, like somehow automatically recovering the original IFS at the end (eg: first char automatically shifted out or something).

                  – Russ
                  Sep 16 '16 at 14:48
















                24












                24








                24







                Here is a simple script to demonstrates the difference between $* and $@:



                #!/bin/bash

                test_param() {
                echo "Receive $# parameters"
                echo Using '$*'

                echo
                for param in $*; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '"$*"'
                for param in "$*"; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '$@'
                for param in $@; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '"$@"';
                for param in "$@"; do
                printf '==>%s<==n' "$param"
                done
                }

                IFS="^${IFS}"

                test_param 1 2 3 "a b c"


                Output:



                % cuonglm at ~
                % bash test.sh
                Receive 4 parameters

                Using $*
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a<==
                ==>b<==
                ==>c<==

                Using "$*"
                ==>1^2^3^a b c<==

                Using $@
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a<==
                ==>b<==
                ==>c<==

                Using "$@"
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a b c<==


                In array syntax, there is no difference when using $* or $@. It only make sense when you use them with double quotes "$*" and "$@".






                share|improve this answer















                Here is a simple script to demonstrates the difference between $* and $@:



                #!/bin/bash

                test_param() {
                echo "Receive $# parameters"
                echo Using '$*'

                echo
                for param in $*; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '"$*"'
                for param in "$*"; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '$@'
                for param in $@; do
                printf '==>%s<==n' "$param"
                done;

                echo
                echo Using '"$@"';
                for param in "$@"; do
                printf '==>%s<==n' "$param"
                done
                }

                IFS="^${IFS}"

                test_param 1 2 3 "a b c"


                Output:



                % cuonglm at ~
                % bash test.sh
                Receive 4 parameters

                Using $*
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a<==
                ==>b<==
                ==>c<==

                Using "$*"
                ==>1^2^3^a b c<==

                Using $@
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a<==
                ==>b<==
                ==>c<==

                Using "$@"
                ==>1<==
                ==>2<==
                ==>3<==
                ==>a b c<==


                In array syntax, there is no difference when using $* or $@. It only make sense when you use them with double quotes "$*" and "$@".







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jan 29 '18 at 0:21









                Jeff Schaller

                43.7k1161141




                43.7k1161141










                answered Oct 8 '13 at 17:18









                cuonglmcuonglm

                105k25209307




                105k25209307













                • Excellent example! Can you explain the use of IFS="^${IFS}", though?

                  – Russ
                  Sep 16 '16 at 12:47











                • @Russ: It show you how value is concat with the first character in IFS.

                  – cuonglm
                  Sep 16 '16 at 13:03











                • In the same way that IFS="^xxxxx" would do? The trailing ${IFS} suffix made me think you were doing something trickier, like somehow automatically recovering the original IFS at the end (eg: first char automatically shifted out or something).

                  – Russ
                  Sep 16 '16 at 14:48





















                • Excellent example! Can you explain the use of IFS="^${IFS}", though?

                  – Russ
                  Sep 16 '16 at 12:47











                • @Russ: It show you how value is concat with the first character in IFS.

                  – cuonglm
                  Sep 16 '16 at 13:03











                • In the same way that IFS="^xxxxx" would do? The trailing ${IFS} suffix made me think you were doing something trickier, like somehow automatically recovering the original IFS at the end (eg: first char automatically shifted out or something).

                  – Russ
                  Sep 16 '16 at 14:48



















                Excellent example! Can you explain the use of IFS="^${IFS}", though?

                – Russ
                Sep 16 '16 at 12:47





                Excellent example! Can you explain the use of IFS="^${IFS}", though?

                – Russ
                Sep 16 '16 at 12:47













                @Russ: It show you how value is concat with the first character in IFS.

                – cuonglm
                Sep 16 '16 at 13:03





                @Russ: It show you how value is concat with the first character in IFS.

                – cuonglm
                Sep 16 '16 at 13:03













                In the same way that IFS="^xxxxx" would do? The trailing ${IFS} suffix made me think you were doing something trickier, like somehow automatically recovering the original IFS at the end (eg: first char automatically shifted out or something).

                – Russ
                Sep 16 '16 at 14:48







                In the same way that IFS="^xxxxx" would do? The trailing ${IFS} suffix made me think you were doing something trickier, like somehow automatically recovering the original IFS at the end (eg: first char automatically shifted out or something).

                – Russ
                Sep 16 '16 at 14:48













                11














                The code you provided will give the same result. To understand it better, try this:



                foo () {
                for i in "$*"; do
                echo "$i"
                done
                }

                bar () {
                for i in "$@"; do
                echo "$i"
                done
                }


                The output should now be different. Here's what I get:



                $ foo() 1 2 3 4
                1 2 3 4
                $ bar() 1 2 3 4
                1
                2
                3
                4


                This worked for me on bash. As far as I know, ksh should not differ much. Essentially, quoting $* will treat everything as one word, and quoting $@ will treat the list as separate words, as can be seen in the example above.



                As an example of using the IFS variable with $*, consider this



                fooifs () {
                IFS="c"
                for i in "$*"; do
                echo "$i"
                done
                unset IFS # reset to the original value
                }


                I get this as a result:



                $ fooifs 1 2 3 4
                1c2c3c4


                Also, I've just confirmed it works the same in ksh. Both bash and ksh tested here were under OSX but I can't see how that would matter much.






                share|improve this answer


























                • "changed within a function - doesn't affect the global". Did you test that?

                  – Mikel
                  Jun 25 '12 at 15:11











                • Yes, I've checked that. For the peace of mind, I'll add the unset IFS at the end to reset it to the original, but it worked for me no problem and doing an echo $IFS resulted in the standard output I get from it. Setting the IFS withing the curly brackets introduces a new scope, so unless you export it, it will not affect the outside IFS.

                  – Wojtek Rzepala
                  Jun 25 '12 at 16:00













                • echo $IFS doesn't prove anything, because the shell sees the ,, but then does word splitting using IFS! Try echo "$IFS".

                  – Mikel
                  Jun 25 '12 at 16:43











                • good point. unsetting IFS should solve that.

                  – Wojtek Rzepala
                  Jun 25 '12 at 17:39











                • Unless IFS had a different custom value before calling the function. But yes, most of the time unsetting IFS will work.

                  – Mikel
                  Jun 25 '12 at 20:51
















                11














                The code you provided will give the same result. To understand it better, try this:



                foo () {
                for i in "$*"; do
                echo "$i"
                done
                }

                bar () {
                for i in "$@"; do
                echo "$i"
                done
                }


                The output should now be different. Here's what I get:



                $ foo() 1 2 3 4
                1 2 3 4
                $ bar() 1 2 3 4
                1
                2
                3
                4


                This worked for me on bash. As far as I know, ksh should not differ much. Essentially, quoting $* will treat everything as one word, and quoting $@ will treat the list as separate words, as can be seen in the example above.



                As an example of using the IFS variable with $*, consider this



                fooifs () {
                IFS="c"
                for i in "$*"; do
                echo "$i"
                done
                unset IFS # reset to the original value
                }


                I get this as a result:



                $ fooifs 1 2 3 4
                1c2c3c4


                Also, I've just confirmed it works the same in ksh. Both bash and ksh tested here were under OSX but I can't see how that would matter much.






                share|improve this answer


























                • "changed within a function - doesn't affect the global". Did you test that?

                  – Mikel
                  Jun 25 '12 at 15:11











                • Yes, I've checked that. For the peace of mind, I'll add the unset IFS at the end to reset it to the original, but it worked for me no problem and doing an echo $IFS resulted in the standard output I get from it. Setting the IFS withing the curly brackets introduces a new scope, so unless you export it, it will not affect the outside IFS.

                  – Wojtek Rzepala
                  Jun 25 '12 at 16:00













                • echo $IFS doesn't prove anything, because the shell sees the ,, but then does word splitting using IFS! Try echo "$IFS".

                  – Mikel
                  Jun 25 '12 at 16:43











                • good point. unsetting IFS should solve that.

                  – Wojtek Rzepala
                  Jun 25 '12 at 17:39











                • Unless IFS had a different custom value before calling the function. But yes, most of the time unsetting IFS will work.

                  – Mikel
                  Jun 25 '12 at 20:51














                11












                11








                11







                The code you provided will give the same result. To understand it better, try this:



                foo () {
                for i in "$*"; do
                echo "$i"
                done
                }

                bar () {
                for i in "$@"; do
                echo "$i"
                done
                }


                The output should now be different. Here's what I get:



                $ foo() 1 2 3 4
                1 2 3 4
                $ bar() 1 2 3 4
                1
                2
                3
                4


                This worked for me on bash. As far as I know, ksh should not differ much. Essentially, quoting $* will treat everything as one word, and quoting $@ will treat the list as separate words, as can be seen in the example above.



                As an example of using the IFS variable with $*, consider this



                fooifs () {
                IFS="c"
                for i in "$*"; do
                echo "$i"
                done
                unset IFS # reset to the original value
                }


                I get this as a result:



                $ fooifs 1 2 3 4
                1c2c3c4


                Also, I've just confirmed it works the same in ksh. Both bash and ksh tested here were under OSX but I can't see how that would matter much.






                share|improve this answer















                The code you provided will give the same result. To understand it better, try this:



                foo () {
                for i in "$*"; do
                echo "$i"
                done
                }

                bar () {
                for i in "$@"; do
                echo "$i"
                done
                }


                The output should now be different. Here's what I get:



                $ foo() 1 2 3 4
                1 2 3 4
                $ bar() 1 2 3 4
                1
                2
                3
                4


                This worked for me on bash. As far as I know, ksh should not differ much. Essentially, quoting $* will treat everything as one word, and quoting $@ will treat the list as separate words, as can be seen in the example above.



                As an example of using the IFS variable with $*, consider this



                fooifs () {
                IFS="c"
                for i in "$*"; do
                echo "$i"
                done
                unset IFS # reset to the original value
                }


                I get this as a result:



                $ fooifs 1 2 3 4
                1c2c3c4


                Also, I've just confirmed it works the same in ksh. Both bash and ksh tested here were under OSX but I can't see how that would matter much.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jun 25 '12 at 21:09

























                answered Jun 25 '12 at 12:26









                Wojtek RzepalaWojtek Rzepala

                1,84411222




                1,84411222













                • "changed within a function - doesn't affect the global". Did you test that?

                  – Mikel
                  Jun 25 '12 at 15:11











                • Yes, I've checked that. For the peace of mind, I'll add the unset IFS at the end to reset it to the original, but it worked for me no problem and doing an echo $IFS resulted in the standard output I get from it. Setting the IFS withing the curly brackets introduces a new scope, so unless you export it, it will not affect the outside IFS.

                  – Wojtek Rzepala
                  Jun 25 '12 at 16:00













                • echo $IFS doesn't prove anything, because the shell sees the ,, but then does word splitting using IFS! Try echo "$IFS".

                  – Mikel
                  Jun 25 '12 at 16:43











                • good point. unsetting IFS should solve that.

                  – Wojtek Rzepala
                  Jun 25 '12 at 17:39











                • Unless IFS had a different custom value before calling the function. But yes, most of the time unsetting IFS will work.

                  – Mikel
                  Jun 25 '12 at 20:51



















                • "changed within a function - doesn't affect the global". Did you test that?

                  – Mikel
                  Jun 25 '12 at 15:11











                • Yes, I've checked that. For the peace of mind, I'll add the unset IFS at the end to reset it to the original, but it worked for me no problem and doing an echo $IFS resulted in the standard output I get from it. Setting the IFS withing the curly brackets introduces a new scope, so unless you export it, it will not affect the outside IFS.

                  – Wojtek Rzepala
                  Jun 25 '12 at 16:00













                • echo $IFS doesn't prove anything, because the shell sees the ,, but then does word splitting using IFS! Try echo "$IFS".

                  – Mikel
                  Jun 25 '12 at 16:43











                • good point. unsetting IFS should solve that.

                  – Wojtek Rzepala
                  Jun 25 '12 at 17:39











                • Unless IFS had a different custom value before calling the function. But yes, most of the time unsetting IFS will work.

                  – Mikel
                  Jun 25 '12 at 20:51

















                "changed within a function - doesn't affect the global". Did you test that?

                – Mikel
                Jun 25 '12 at 15:11





                "changed within a function - doesn't affect the global". Did you test that?

                – Mikel
                Jun 25 '12 at 15:11













                Yes, I've checked that. For the peace of mind, I'll add the unset IFS at the end to reset it to the original, but it worked for me no problem and doing an echo $IFS resulted in the standard output I get from it. Setting the IFS withing the curly brackets introduces a new scope, so unless you export it, it will not affect the outside IFS.

                – Wojtek Rzepala
                Jun 25 '12 at 16:00







                Yes, I've checked that. For the peace of mind, I'll add the unset IFS at the end to reset it to the original, but it worked for me no problem and doing an echo $IFS resulted in the standard output I get from it. Setting the IFS withing the curly brackets introduces a new scope, so unless you export it, it will not affect the outside IFS.

                – Wojtek Rzepala
                Jun 25 '12 at 16:00















                echo $IFS doesn't prove anything, because the shell sees the ,, but then does word splitting using IFS! Try echo "$IFS".

                – Mikel
                Jun 25 '12 at 16:43





                echo $IFS doesn't prove anything, because the shell sees the ,, but then does word splitting using IFS! Try echo "$IFS".

                – Mikel
                Jun 25 '12 at 16:43













                good point. unsetting IFS should solve that.

                – Wojtek Rzepala
                Jun 25 '12 at 17:39





                good point. unsetting IFS should solve that.

                – Wojtek Rzepala
                Jun 25 '12 at 17:39













                Unless IFS had a different custom value before calling the function. But yes, most of the time unsetting IFS will work.

                – Mikel
                Jun 25 '12 at 20:51





                Unless IFS had a different custom value before calling the function. But yes, most of the time unsetting IFS will work.

                – Mikel
                Jun 25 '12 at 20:51











                6














                The difference is important when writing scripts that should use the positional parameters in the right way...



                Imagine the following call:



                $ myuseradd -m -c "Carlos Campderrós" ccampderros


                Here there are just 4 parameters:



                $1 => -m
                $2 => -c
                $3 => Carlos Campderrós
                $4 => ccampderros


                In my case, myuseradd is just a wrapper for useradd that accepts the same parameters, but adds a quota for the user:



                #!/bin/bash -e

                useradd "$@"
                setquota -u "${!#}" 10000 11000 1000 1100


                Notice the call to useradd "$@", with $@ quoted. This will respect the parameters and send them as-they-are to useradd. If you were to unquote $@ (or to use $* also unquoted), useradd would see 5 parameters, as the 3rd parameter which contained a space would be split in two:



                $1 => -m
                $2 => -c
                $3 => Carlos
                $4 => Campderrós
                $5 => ccampderros


                (and conversely, if you were to use "$*", useradd would only see one parameter: -m -c Carlos Campderrós ccampderros)



                So, in short, if you need to work with parameters respecting multi-word parameters, use "$@".






                share|improve this answer




























                  6














                  The difference is important when writing scripts that should use the positional parameters in the right way...



                  Imagine the following call:



                  $ myuseradd -m -c "Carlos Campderrós" ccampderros


                  Here there are just 4 parameters:



                  $1 => -m
                  $2 => -c
                  $3 => Carlos Campderrós
                  $4 => ccampderros


                  In my case, myuseradd is just a wrapper for useradd that accepts the same parameters, but adds a quota for the user:



                  #!/bin/bash -e

                  useradd "$@"
                  setquota -u "${!#}" 10000 11000 1000 1100


                  Notice the call to useradd "$@", with $@ quoted. This will respect the parameters and send them as-they-are to useradd. If you were to unquote $@ (or to use $* also unquoted), useradd would see 5 parameters, as the 3rd parameter which contained a space would be split in two:



                  $1 => -m
                  $2 => -c
                  $3 => Carlos
                  $4 => Campderrós
                  $5 => ccampderros


                  (and conversely, if you were to use "$*", useradd would only see one parameter: -m -c Carlos Campderrós ccampderros)



                  So, in short, if you need to work with parameters respecting multi-word parameters, use "$@".






                  share|improve this answer


























                    6












                    6








                    6







                    The difference is important when writing scripts that should use the positional parameters in the right way...



                    Imagine the following call:



                    $ myuseradd -m -c "Carlos Campderrós" ccampderros


                    Here there are just 4 parameters:



                    $1 => -m
                    $2 => -c
                    $3 => Carlos Campderrós
                    $4 => ccampderros


                    In my case, myuseradd is just a wrapper for useradd that accepts the same parameters, but adds a quota for the user:



                    #!/bin/bash -e

                    useradd "$@"
                    setquota -u "${!#}" 10000 11000 1000 1100


                    Notice the call to useradd "$@", with $@ quoted. This will respect the parameters and send them as-they-are to useradd. If you were to unquote $@ (or to use $* also unquoted), useradd would see 5 parameters, as the 3rd parameter which contained a space would be split in two:



                    $1 => -m
                    $2 => -c
                    $3 => Carlos
                    $4 => Campderrós
                    $5 => ccampderros


                    (and conversely, if you were to use "$*", useradd would only see one parameter: -m -c Carlos Campderrós ccampderros)



                    So, in short, if you need to work with parameters respecting multi-word parameters, use "$@".






                    share|improve this answer













                    The difference is important when writing scripts that should use the positional parameters in the right way...



                    Imagine the following call:



                    $ myuseradd -m -c "Carlos Campderrós" ccampderros


                    Here there are just 4 parameters:



                    $1 => -m
                    $2 => -c
                    $3 => Carlos Campderrós
                    $4 => ccampderros


                    In my case, myuseradd is just a wrapper for useradd that accepts the same parameters, but adds a quota for the user:



                    #!/bin/bash -e

                    useradd "$@"
                    setquota -u "${!#}" 10000 11000 1000 1100


                    Notice the call to useradd "$@", with $@ quoted. This will respect the parameters and send them as-they-are to useradd. If you were to unquote $@ (or to use $* also unquoted), useradd would see 5 parameters, as the 3rd parameter which contained a space would be split in two:



                    $1 => -m
                    $2 => -c
                    $3 => Carlos
                    $4 => Campderrós
                    $5 => ccampderros


                    (and conversely, if you were to use "$*", useradd would only see one parameter: -m -c Carlos Campderrós ccampderros)



                    So, in short, if you need to work with parameters respecting multi-word parameters, use "$@".







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jun 25 '12 at 14:55









                    Carlos CampderrósCarlos Campderrós

                    8711716




                    8711716























                        4














                           *      Expands  to  the positional parameters, starting from one.  When
                        the expansion occurs within double quotes, it expands to a sin‐
                        gle word with the value of each parameter separated by the first
                        character of the IFS special variable. That is, "$*" is equiva‐
                        lent to "$1c$2c...", where c is the first character of the value
                        of the IFS variable. If IFS is unset, the parameters are sepa‐
                        rated by spaces. If IFS is null, the parameters are joined
                        without intervening separators.
                        @ Expands to the positional parameters, starting from one. When
                        the expansion occurs within double quotes, each parameter
                        expands to a separate word. That is, "$@" is equivalent to "$1"
                        "$2" ... If the double-quoted expansion occurs within a word,
                        the expansion of the first parameter is joined with the begin‐
                        ning part of the original word, and the expansion of the last
                        parameter is joined with the last part of the original word.
                        When there are no positional parameters, "$@" and $@ expand to
                        nothing (i.e., they are removed).


                        // man bash . is ksh, afair, similar behaviour.






                        share|improve this answer




























                          4














                             *      Expands  to  the positional parameters, starting from one.  When
                          the expansion occurs within double quotes, it expands to a sin‐
                          gle word with the value of each parameter separated by the first
                          character of the IFS special variable. That is, "$*" is equiva‐
                          lent to "$1c$2c...", where c is the first character of the value
                          of the IFS variable. If IFS is unset, the parameters are sepa‐
                          rated by spaces. If IFS is null, the parameters are joined
                          without intervening separators.
                          @ Expands to the positional parameters, starting from one. When
                          the expansion occurs within double quotes, each parameter
                          expands to a separate word. That is, "$@" is equivalent to "$1"
                          "$2" ... If the double-quoted expansion occurs within a word,
                          the expansion of the first parameter is joined with the begin‐
                          ning part of the original word, and the expansion of the last
                          parameter is joined with the last part of the original word.
                          When there are no positional parameters, "$@" and $@ expand to
                          nothing (i.e., they are removed).


                          // man bash . is ksh, afair, similar behaviour.






                          share|improve this answer


























                            4












                            4








                            4







                               *      Expands  to  the positional parameters, starting from one.  When
                            the expansion occurs within double quotes, it expands to a sin‐
                            gle word with the value of each parameter separated by the first
                            character of the IFS special variable. That is, "$*" is equiva‐
                            lent to "$1c$2c...", where c is the first character of the value
                            of the IFS variable. If IFS is unset, the parameters are sepa‐
                            rated by spaces. If IFS is null, the parameters are joined
                            without intervening separators.
                            @ Expands to the positional parameters, starting from one. When
                            the expansion occurs within double quotes, each parameter
                            expands to a separate word. That is, "$@" is equivalent to "$1"
                            "$2" ... If the double-quoted expansion occurs within a word,
                            the expansion of the first parameter is joined with the begin‐
                            ning part of the original word, and the expansion of the last
                            parameter is joined with the last part of the original word.
                            When there are no positional parameters, "$@" and $@ expand to
                            nothing (i.e., they are removed).


                            // man bash . is ksh, afair, similar behaviour.






                            share|improve this answer













                               *      Expands  to  the positional parameters, starting from one.  When
                            the expansion occurs within double quotes, it expands to a sin‐
                            gle word with the value of each parameter separated by the first
                            character of the IFS special variable. That is, "$*" is equiva‐
                            lent to "$1c$2c...", where c is the first character of the value
                            of the IFS variable. If IFS is unset, the parameters are sepa‐
                            rated by spaces. If IFS is null, the parameters are joined
                            without intervening separators.
                            @ Expands to the positional parameters, starting from one. When
                            the expansion occurs within double quotes, each parameter
                            expands to a separate word. That is, "$@" is equivalent to "$1"
                            "$2" ... If the double-quoted expansion occurs within a word,
                            the expansion of the first parameter is joined with the begin‐
                            ning part of the original word, and the expansion of the last
                            parameter is joined with the last part of the original word.
                            When there are no positional parameters, "$@" and $@ expand to
                            nothing (i.e., they are removed).


                            // man bash . is ksh, afair, similar behaviour.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jun 25 '12 at 10:13









                            rushrush

                            19.3k46596




                            19.3k46596























                                2














                                Talking about differences between zsh and bash:



                                With quotes around $@ and $*, zsh and bash behave the same, and I guess the result is quite standard among all shells:



                                 $ f () { for i in "$@"; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a+
                                +b+
                                ++
                                $ f () { for i in "$*"; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a b +


                                Without quotes, results are the same for $* and $@, but different in bash and in zsh. In this case zsh shows some odd behaviour:



                                bash$ f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a+
                                +a+
                                +b+
                                zsh% f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a+
                                +b+


                                (Zsh usually don't split textual data using IFS, unless explicitly requested, but notice that here the empty argument is unexpectedly missing in the list.)






                                share|improve this answer





















                                • 1





                                  In zsh, $@ isn't special in this respect: $x expands to at most one word, but empty variables expand to nothing (not an empty word). Try print -l a $foo b with foo empty or undefined.

                                  – Gilles
                                  Jun 25 '12 at 23:27
















                                2














                                Talking about differences between zsh and bash:



                                With quotes around $@ and $*, zsh and bash behave the same, and I guess the result is quite standard among all shells:



                                 $ f () { for i in "$@"; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a+
                                +b+
                                ++
                                $ f () { for i in "$*"; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a b +


                                Without quotes, results are the same for $* and $@, but different in bash and in zsh. In this case zsh shows some odd behaviour:



                                bash$ f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a+
                                +a+
                                +b+
                                zsh% f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a+
                                +b+


                                (Zsh usually don't split textual data using IFS, unless explicitly requested, but notice that here the empty argument is unexpectedly missing in the list.)






                                share|improve this answer





















                                • 1





                                  In zsh, $@ isn't special in this respect: $x expands to at most one word, but empty variables expand to nothing (not an empty word). Try print -l a $foo b with foo empty or undefined.

                                  – Gilles
                                  Jun 25 '12 at 23:27














                                2












                                2








                                2







                                Talking about differences between zsh and bash:



                                With quotes around $@ and $*, zsh and bash behave the same, and I guess the result is quite standard among all shells:



                                 $ f () { for i in "$@"; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a+
                                +b+
                                ++
                                $ f () { for i in "$*"; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a b +


                                Without quotes, results are the same for $* and $@, but different in bash and in zsh. In this case zsh shows some odd behaviour:



                                bash$ f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a+
                                +a+
                                +b+
                                zsh% f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a+
                                +b+


                                (Zsh usually don't split textual data using IFS, unless explicitly requested, but notice that here the empty argument is unexpectedly missing in the list.)






                                share|improve this answer















                                Talking about differences between zsh and bash:



                                With quotes around $@ and $*, zsh and bash behave the same, and I guess the result is quite standard among all shells:



                                 $ f () { for i in "$@"; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a+
                                +b+
                                ++
                                $ f () { for i in "$*"; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a b +


                                Without quotes, results are the same for $* and $@, but different in bash and in zsh. In this case zsh shows some odd behaviour:



                                bash$ f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a+
                                +a+
                                +b+
                                zsh% f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
                                +a a+
                                +b+


                                (Zsh usually don't split textual data using IFS, unless explicitly requested, but notice that here the empty argument is unexpectedly missing in the list.)







                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited Jun 25 '12 at 13:02

























                                answered Jun 25 '12 at 12:56









                                Stéphane GimenezStéphane Gimenez

                                19.6k25174




                                19.6k25174








                                • 1





                                  In zsh, $@ isn't special in this respect: $x expands to at most one word, but empty variables expand to nothing (not an empty word). Try print -l a $foo b with foo empty or undefined.

                                  – Gilles
                                  Jun 25 '12 at 23:27














                                • 1





                                  In zsh, $@ isn't special in this respect: $x expands to at most one word, but empty variables expand to nothing (not an empty word). Try print -l a $foo b with foo empty or undefined.

                                  – Gilles
                                  Jun 25 '12 at 23:27








                                1




                                1





                                In zsh, $@ isn't special in this respect: $x expands to at most one word, but empty variables expand to nothing (not an empty word). Try print -l a $foo b with foo empty or undefined.

                                – Gilles
                                Jun 25 '12 at 23:27





                                In zsh, $@ isn't special in this respect: $x expands to at most one word, but empty variables expand to nothing (not an empty word). Try print -l a $foo b with foo empty or undefined.

                                – Gilles
                                Jun 25 '12 at 23:27











                                0














                                One of the answers says $* (which I think of as a "splat") is rarely useful.



                                I search google with G() { IFS='+' ; w3m "https://encrypted.google.com/search?q=$*" ; }



                                Since URL’s are often split with a +, but my keyboard makes   easier to reach than +, $* + $IFS feel worthwhile.






                                share|improve this answer




























                                  0














                                  One of the answers says $* (which I think of as a "splat") is rarely useful.



                                  I search google with G() { IFS='+' ; w3m "https://encrypted.google.com/search?q=$*" ; }



                                  Since URL’s are often split with a +, but my keyboard makes   easier to reach than +, $* + $IFS feel worthwhile.






                                  share|improve this answer


























                                    0












                                    0








                                    0







                                    One of the answers says $* (which I think of as a "splat") is rarely useful.



                                    I search google with G() { IFS='+' ; w3m "https://encrypted.google.com/search?q=$*" ; }



                                    Since URL’s are often split with a +, but my keyboard makes   easier to reach than +, $* + $IFS feel worthwhile.






                                    share|improve this answer













                                    One of the answers says $* (which I think of as a "splat") is rarely useful.



                                    I search google with G() { IFS='+' ; w3m "https://encrypted.google.com/search?q=$*" ; }



                                    Since URL’s are often split with a +, but my keyboard makes   easier to reach than +, $* + $IFS feel worthwhile.







                                    share|improve this answer












                                    share|improve this answer



                                    share|improve this answer










                                    answered Mar 9 at 2:01









                                    isomorphismesisomorphismes

                                    437412




                                    437412






























                                        draft saved

                                        draft discarded




















































                                        Thanks for contributing an answer to Unix & Linux Stack Exchange!


                                        • Please be sure to answer the question. Provide details and share your research!

                                        But avoid



                                        • Asking for help, clarification, or responding to other answers.

                                        • Making statements based on opinion; back them up with references or personal experience.


                                        To learn more, see our tips on writing great answers.




                                        draft saved


                                        draft discarded














                                        StackExchange.ready(
                                        function () {
                                        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f41571%2fwhat-is-the-difference-between-and%23new-answer', 'question_page');
                                        }
                                        );

                                        Post as a guest















                                        Required, but never shown





















































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown

































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown







                                        Popular posts from this blog

                                        How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

                                        is 'sed' thread safe

                                        How to make a Squid Proxy server?