What is the data structure of $@ in shell?What is the difference between $* and $@?A shell tool to...

ST_Buffer in PostGIS produces different results for the same set of lines

Why publish a research paper when a blog post or a lecture slide can have more citation count than a journal paper?

"on its way" vs. "in its way"

Cookies - Should the toggles be on?

Words and Words with "ver-" Prefix

How to deal with possible delayed baggage?

If I delete my router's history can my ISP still provide it to my parents?

Why do cars have plastic shrouds over the engine?

Why avoid shared user accounts?

A Missing Symbol for This Logo

How should I handle players who ignore the session zero agreement?

Why did Luke use his left hand to shoot?

When can a QA tester start his job?

Why did the villain in the first Men in Black movie care about Earth's Cockroaches?

Square Root Distance from Integers

How to make ice magic work from a scientific point of view?

Alien invasion to probe us, why?

How to play electric guitar and bass as a duet

Potential client has a problematic employee I can't work with

Is a new Boolean field better than a null reference when a value can be meaningfully absent?

Why does magnet wire need to be insulated?

How to not let the Identify spell spoil everything?

General past possibility with 'could'

Is Krishna the only avatar among dashavatara who had more than one wife?



What is the data structure of $@ in shell?


What is the difference between $* and $@?A shell tool to “tablify” input dataShell script Variable StructureShell command to get all the files from a complex directory structureshell script to do some text manipulation of text file data structure and slight content changesSplit the file and put it in corresponding data structure?Why *not* parse `ls` (and what do to instead)?What does $( … ) mean in the shell?Set data structure equivalent in bash shell?What does “structure needs cleaning mean”?Speeding up repeated python calls (or, alternatively, porting a complex regex to sed)













5















We usually use $@ to represent all of argument except $0. However, I don't know what data structure $@ is.



Why it behave differently with $* when including in double quote, could anyone give me a interpreter-level explanation?



It can be iterated in for loop, so it seems to be array.
However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown. Due to the limitation of shell, I cannot write more experiment code to carry it out.



Difference between this post: This post show how $@ behaves differently from $*. But I am wondering about the data type of $@. Shell as a interpreting language, like Python, should representing data according to a series of fundamental types. Or in other words, I want to know how $@ stored in computer memory.



Is it a string, a multi-line string or a array?



If it is a unique data type, is it possible to define a custom variable as an instance of this type?










share|improve this question




















  • 1





    Possible duplicate of What is the difference between $* and $@?

    – Haxiel
    6 hours ago











  • @Haxiel, I don't think so, I wrote their difference at the bottom of my post.

    – davmos
    5 hours ago











  • You would be better served by testing the difference in output with printf '%sn' "$@" and printf '%sn' "$*". The echo utility just outputs its arguments, no matter if they are one or many. Both are arrays (of strings), but they behave differently when double quoted. If either was a multi-line string, then they would not be able to store multi-line strings (which they can). It's unclear what issue you are trying to solve.

    – Kusalananda
    5 hours ago













  • "However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown." -- You can also do a=(a b c); echo "${a[@]}" in the shell, or @a=(1, 2, 4); print @a; in Perl, or a=[1,2,3]; print(a) in Python. All will output the whole array/list with one command.

    – ilkkachu
    5 hours ago








  • 1





    Your question is the equivalent of asking what a @var variable is in Perl, in terms of its underlying storage. From the point view of an ordinary Perl program, it does not really matter, other than that it's accessible as an array/list (and the fact that there are contexts in which a list is expected).

    – Kusalananda
    5 hours ago


















5















We usually use $@ to represent all of argument except $0. However, I don't know what data structure $@ is.



Why it behave differently with $* when including in double quote, could anyone give me a interpreter-level explanation?



It can be iterated in for loop, so it seems to be array.
However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown. Due to the limitation of shell, I cannot write more experiment code to carry it out.



Difference between this post: This post show how $@ behaves differently from $*. But I am wondering about the data type of $@. Shell as a interpreting language, like Python, should representing data according to a series of fundamental types. Or in other words, I want to know how $@ stored in computer memory.



Is it a string, a multi-line string or a array?



If it is a unique data type, is it possible to define a custom variable as an instance of this type?










share|improve this question




















  • 1





    Possible duplicate of What is the difference between $* and $@?

    – Haxiel
    6 hours ago











  • @Haxiel, I don't think so, I wrote their difference at the bottom of my post.

    – davmos
    5 hours ago











  • You would be better served by testing the difference in output with printf '%sn' "$@" and printf '%sn' "$*". The echo utility just outputs its arguments, no matter if they are one or many. Both are arrays (of strings), but they behave differently when double quoted. If either was a multi-line string, then they would not be able to store multi-line strings (which they can). It's unclear what issue you are trying to solve.

    – Kusalananda
    5 hours ago













  • "However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown." -- You can also do a=(a b c); echo "${a[@]}" in the shell, or @a=(1, 2, 4); print @a; in Perl, or a=[1,2,3]; print(a) in Python. All will output the whole array/list with one command.

    – ilkkachu
    5 hours ago








  • 1





    Your question is the equivalent of asking what a @var variable is in Perl, in terms of its underlying storage. From the point view of an ordinary Perl program, it does not really matter, other than that it's accessible as an array/list (and the fact that there are contexts in which a list is expected).

    – Kusalananda
    5 hours ago
















5












5








5


1






We usually use $@ to represent all of argument except $0. However, I don't know what data structure $@ is.



Why it behave differently with $* when including in double quote, could anyone give me a interpreter-level explanation?



It can be iterated in for loop, so it seems to be array.
However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown. Due to the limitation of shell, I cannot write more experiment code to carry it out.



Difference between this post: This post show how $@ behaves differently from $*. But I am wondering about the data type of $@. Shell as a interpreting language, like Python, should representing data according to a series of fundamental types. Or in other words, I want to know how $@ stored in computer memory.



Is it a string, a multi-line string or a array?



If it is a unique data type, is it possible to define a custom variable as an instance of this type?










share|improve this question
















We usually use $@ to represent all of argument except $0. However, I don't know what data structure $@ is.



Why it behave differently with $* when including in double quote, could anyone give me a interpreter-level explanation?



It can be iterated in for loop, so it seems to be array.
However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown. Due to the limitation of shell, I cannot write more experiment code to carry it out.



Difference between this post: This post show how $@ behaves differently from $*. But I am wondering about the data type of $@. Shell as a interpreting language, like Python, should representing data according to a series of fundamental types. Or in other words, I want to know how $@ stored in computer memory.



Is it a string, a multi-line string or a array?



If it is a unique data type, is it possible to define a custom variable as an instance of this type?







bash shell






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 5 hours ago







davmos

















asked 6 hours ago









davmosdavmos

3614




3614








  • 1





    Possible duplicate of What is the difference between $* and $@?

    – Haxiel
    6 hours ago











  • @Haxiel, I don't think so, I wrote their difference at the bottom of my post.

    – davmos
    5 hours ago











  • You would be better served by testing the difference in output with printf '%sn' "$@" and printf '%sn' "$*". The echo utility just outputs its arguments, no matter if they are one or many. Both are arrays (of strings), but they behave differently when double quoted. If either was a multi-line string, then they would not be able to store multi-line strings (which they can). It's unclear what issue you are trying to solve.

    – Kusalananda
    5 hours ago













  • "However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown." -- You can also do a=(a b c); echo "${a[@]}" in the shell, or @a=(1, 2, 4); print @a; in Perl, or a=[1,2,3]; print(a) in Python. All will output the whole array/list with one command.

    – ilkkachu
    5 hours ago








  • 1





    Your question is the equivalent of asking what a @var variable is in Perl, in terms of its underlying storage. From the point view of an ordinary Perl program, it does not really matter, other than that it's accessible as an array/list (and the fact that there are contexts in which a list is expected).

    – Kusalananda
    5 hours ago
















  • 1





    Possible duplicate of What is the difference between $* and $@?

    – Haxiel
    6 hours ago











  • @Haxiel, I don't think so, I wrote their difference at the bottom of my post.

    – davmos
    5 hours ago











  • You would be better served by testing the difference in output with printf '%sn' "$@" and printf '%sn' "$*". The echo utility just outputs its arguments, no matter if they are one or many. Both are arrays (of strings), but they behave differently when double quoted. If either was a multi-line string, then they would not be able to store multi-line strings (which they can). It's unclear what issue you are trying to solve.

    – Kusalananda
    5 hours ago













  • "However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown." -- You can also do a=(a b c); echo "${a[@]}" in the shell, or @a=(1, 2, 4); print @a; in Perl, or a=[1,2,3]; print(a) in Python. All will output the whole array/list with one command.

    – ilkkachu
    5 hours ago








  • 1





    Your question is the equivalent of asking what a @var variable is in Perl, in terms of its underlying storage. From the point view of an ordinary Perl program, it does not really matter, other than that it's accessible as an array/list (and the fact that there are contexts in which a list is expected).

    – Kusalananda
    5 hours ago










1




1





Possible duplicate of What is the difference between $* and $@?

– Haxiel
6 hours ago





Possible duplicate of What is the difference between $* and $@?

– Haxiel
6 hours ago













@Haxiel, I don't think so, I wrote their difference at the bottom of my post.

– davmos
5 hours ago





@Haxiel, I don't think so, I wrote their difference at the bottom of my post.

– davmos
5 hours ago













You would be better served by testing the difference in output with printf '%sn' "$@" and printf '%sn' "$*". The echo utility just outputs its arguments, no matter if they are one or many. Both are arrays (of strings), but they behave differently when double quoted. If either was a multi-line string, then they would not be able to store multi-line strings (which they can). It's unclear what issue you are trying to solve.

– Kusalananda
5 hours ago







You would be better served by testing the difference in output with printf '%sn' "$@" and printf '%sn' "$*". The echo utility just outputs its arguments, no matter if they are one or many. Both are arrays (of strings), but they behave differently when double quoted. If either was a multi-line string, then they would not be able to store multi-line strings (which they can). It's unclear what issue you are trying to solve.

– Kusalananda
5 hours ago















"However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown." -- You can also do a=(a b c); echo "${a[@]}" in the shell, or @a=(1, 2, 4); print @a; in Perl, or a=[1,2,3]; print(a) in Python. All will output the whole array/list with one command.

– ilkkachu
5 hours ago







"However, it can also echoed entirely with simple echo $@, if it is an array, only first element will be shown." -- You can also do a=(a b c); echo "${a[@]}" in the shell, or @a=(1, 2, 4); print @a; in Perl, or a=[1,2,3]; print(a) in Python. All will output the whole array/list with one command.

– ilkkachu
5 hours ago






1




1





Your question is the equivalent of asking what a @var variable is in Perl, in terms of its underlying storage. From the point view of an ordinary Perl program, it does not really matter, other than that it's accessible as an array/list (and the fact that there are contexts in which a list is expected).

– Kusalananda
5 hours ago







Your question is the equivalent of asking what a @var variable is in Perl, in terms of its underlying storage. From the point view of an ordinary Perl program, it does not really matter, other than that it's accessible as an array/list (and the fact that there are contexts in which a list is expected).

– Kusalananda
5 hours ago












2 Answers
2






active

oldest

votes


















6














That started as a hack in the Bourne shell. In the Bourne shell, IFS word splitting was done (after tokenisation) on all words in list context (command line arguments or the words the for loops loop on). If you had:



IFS=i var=file2.txt
edit file.txt $var


That second line would be tokenised in 3 words, $var would be expanded, and split+glob would be done on all three words, so you would end up running ed with t, f, le.txt, f, le2.txt as arguments.



Quoting parts of that would prevent the split+glob. That Bourne shell initially remembered which characters were quoted by setting the 8th bit on them internally (that changed later when Unix became 8bit clean, but the shell still did something similar to remember which byte was quoted).



Both $* and $@ were the concatenation of the positional parameters with space in-between. But there was a special processing of $@ when quoted. If $1 contained foo bar and $2 contained baz, "$@" would expand to:



foo bar baz
^^^^^^^ ^^^


Where the first space was quoted (had the 8th bit set) but not the second one (the one added in-between words).



And it's the IFS splitting that takes care of separating the arguments (assuming the space character is in $IFS). That's similar to how $* was expanded in its predecessor the Mashey shell (itself based on the Thomson shell, while the Bourne shell was written from scratch).



That explains why in the Bourne shell initially "$@" would expand to the empty string instead of nothing at all (you had to work around it with ${1+"$@"}) and why "$@" didn't work when $IFS didn't contain the space character.



The intention was to be able to pass the list of arguments verbatim to another command, but that didn't work properly for the empty list or when $IFS didn't contain space.



The Korn shell (on which the POSIX spec is based) changed that behaviour in a few ways:




  • IFS splitting is only done on the result of unquoted expansions (not on edit or file.txt in the example above)


  • $* and $@ are joined with the first character of $IFS or space when $IFS is empty except that for a quoted "$@", that joiner is unquoted like in the Bourne shell, and for a quoted "$*" when IFS is empty, the positional parameters are appended without separator.

  • it added support for arrays, and with ${array[@]} ${array[*]} reminiscent of Bourne's $* and $@ but starting at indice 0 instead of 1, and sparse (more like associative arrays) which means $@ cannot really be treated as a ksh array (compare with csh/rc/zsh/fish/yash where $argv/$* are normal array).


  • "$@" when $# is 0 now expands to nothing instead of the empty string, "$@" works when $IFS doesn't contain spaces except when IFS is empty. An unquoted $* without wildcards expands to one argument (where the positional parameters are joined with space) when $IFS is empty.


ksh93 fixed the remaining few problems above. In ksh93, $* and $@ expands to the list of positional parameters, separated regardless of the value of $IFS, and then further split+globbed+brace-expanded in list contexts, $* joined with first byte (not character) of $IFS, "$@" in list contexts expands to the list of positional parameters, regardless of the value of $IFS. In non-list context, like in var=$@, $@ is joined with space regardless of the value of $IFS.



bash's arrays are designed after the ksh ones. The differences are:




  • no brace-expand upon unquoted expansion

  • first character of $IFS instead of for byte

  • some corner case differences like the expansion of $* when non-quoted in non-list context when $IFS is empty.


While the POSIX spec used to be pretty vague, it now more or less specifies the bash behaviour.



It's different from normal arrays in ksh or bash in that:




  • Indices start at 1 instead of 0 (except in "${@:0}" which includes $0 (not a positional parameter, and in functions gives you the name of the function or not depending on the shell and how the function was defined)).

  • You can't elements individually

  • it's not sparse, you can't unset elements individually


  • shift can be used.


In zsh or yash where arrays are normal arrays (not sparse, indices start at one like in all other shells but ksh/bash), $* is treated as a normal array. zsh has $argv as an alias for it (for compatibility with csh). $* is the same as $argv or ${argv[*]} (arguments joined with the first character of $IFS but still separated out in list contexts). "$@" like "${argv[@]}" or "${*[@]}"} undergoes the Korn-style special processing.






share|improve this answer

































    1















    However, I don't know what data structure $@ is.




    It's a special parameter that expands to the values of the positional parameters...



    Taking the positional parameters as parts of $@, it has a number of distinct elements ($1, $2...), that can be accessed independently and are named by consecutive natural numbers. That would make it seem a lot like something called an array.



    The syntax is a bit weird, though, and even limited. There's no way to modify a single element of the array at a time, the whole thing has to be set at once. (You can use set -- "$@" foo to append a value, or set -- "${@:1:2}" foo "${@:3}" in some shells, to add a value in the middle, but you can't set the elements individually.)




    Why it behave differently with $* when including in double quote,




    Because they're defined to behave differently.




    Or in other words, I want to know how $@ stored in computer memory.




    That depends on the implementation, you'll have to look the source code of any particular shell you care about.




    Is it a string, a multi-line string or a array?




    An array, mostly. Though different from the ksh-style named arrays, since they
    can have arbitrary nonnegative integers as indexes, not just consecutive ones as with $@.



    It's not a single string, since it can be expanded to distinct elements, and calling the elements lines is also not right, since any regular variable, or one of the positional parameters (elements of $@) can also contain newlines.




    If it is a unique data type, is it possible to define a custom variable as an instance of this type?




    No.






    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%2f503303%2fwhat-is-the-data-structure-of-in-shell%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      6














      That started as a hack in the Bourne shell. In the Bourne shell, IFS word splitting was done (after tokenisation) on all words in list context (command line arguments or the words the for loops loop on). If you had:



      IFS=i var=file2.txt
      edit file.txt $var


      That second line would be tokenised in 3 words, $var would be expanded, and split+glob would be done on all three words, so you would end up running ed with t, f, le.txt, f, le2.txt as arguments.



      Quoting parts of that would prevent the split+glob. That Bourne shell initially remembered which characters were quoted by setting the 8th bit on them internally (that changed later when Unix became 8bit clean, but the shell still did something similar to remember which byte was quoted).



      Both $* and $@ were the concatenation of the positional parameters with space in-between. But there was a special processing of $@ when quoted. If $1 contained foo bar and $2 contained baz, "$@" would expand to:



      foo bar baz
      ^^^^^^^ ^^^


      Where the first space was quoted (had the 8th bit set) but not the second one (the one added in-between words).



      And it's the IFS splitting that takes care of separating the arguments (assuming the space character is in $IFS). That's similar to how $* was expanded in its predecessor the Mashey shell (itself based on the Thomson shell, while the Bourne shell was written from scratch).



      That explains why in the Bourne shell initially "$@" would expand to the empty string instead of nothing at all (you had to work around it with ${1+"$@"}) and why "$@" didn't work when $IFS didn't contain the space character.



      The intention was to be able to pass the list of arguments verbatim to another command, but that didn't work properly for the empty list or when $IFS didn't contain space.



      The Korn shell (on which the POSIX spec is based) changed that behaviour in a few ways:




      • IFS splitting is only done on the result of unquoted expansions (not on edit or file.txt in the example above)


      • $* and $@ are joined with the first character of $IFS or space when $IFS is empty except that for a quoted "$@", that joiner is unquoted like in the Bourne shell, and for a quoted "$*" when IFS is empty, the positional parameters are appended without separator.

      • it added support for arrays, and with ${array[@]} ${array[*]} reminiscent of Bourne's $* and $@ but starting at indice 0 instead of 1, and sparse (more like associative arrays) which means $@ cannot really be treated as a ksh array (compare with csh/rc/zsh/fish/yash where $argv/$* are normal array).


      • "$@" when $# is 0 now expands to nothing instead of the empty string, "$@" works when $IFS doesn't contain spaces except when IFS is empty. An unquoted $* without wildcards expands to one argument (where the positional parameters are joined with space) when $IFS is empty.


      ksh93 fixed the remaining few problems above. In ksh93, $* and $@ expands to the list of positional parameters, separated regardless of the value of $IFS, and then further split+globbed+brace-expanded in list contexts, $* joined with first byte (not character) of $IFS, "$@" in list contexts expands to the list of positional parameters, regardless of the value of $IFS. In non-list context, like in var=$@, $@ is joined with space regardless of the value of $IFS.



      bash's arrays are designed after the ksh ones. The differences are:




      • no brace-expand upon unquoted expansion

      • first character of $IFS instead of for byte

      • some corner case differences like the expansion of $* when non-quoted in non-list context when $IFS is empty.


      While the POSIX spec used to be pretty vague, it now more or less specifies the bash behaviour.



      It's different from normal arrays in ksh or bash in that:




      • Indices start at 1 instead of 0 (except in "${@:0}" which includes $0 (not a positional parameter, and in functions gives you the name of the function or not depending on the shell and how the function was defined)).

      • You can't elements individually

      • it's not sparse, you can't unset elements individually


      • shift can be used.


      In zsh or yash where arrays are normal arrays (not sparse, indices start at one like in all other shells but ksh/bash), $* is treated as a normal array. zsh has $argv as an alias for it (for compatibility with csh). $* is the same as $argv or ${argv[*]} (arguments joined with the first character of $IFS but still separated out in list contexts). "$@" like "${argv[@]}" or "${*[@]}"} undergoes the Korn-style special processing.






      share|improve this answer






























        6














        That started as a hack in the Bourne shell. In the Bourne shell, IFS word splitting was done (after tokenisation) on all words in list context (command line arguments or the words the for loops loop on). If you had:



        IFS=i var=file2.txt
        edit file.txt $var


        That second line would be tokenised in 3 words, $var would be expanded, and split+glob would be done on all three words, so you would end up running ed with t, f, le.txt, f, le2.txt as arguments.



        Quoting parts of that would prevent the split+glob. That Bourne shell initially remembered which characters were quoted by setting the 8th bit on them internally (that changed later when Unix became 8bit clean, but the shell still did something similar to remember which byte was quoted).



        Both $* and $@ were the concatenation of the positional parameters with space in-between. But there was a special processing of $@ when quoted. If $1 contained foo bar and $2 contained baz, "$@" would expand to:



        foo bar baz
        ^^^^^^^ ^^^


        Where the first space was quoted (had the 8th bit set) but not the second one (the one added in-between words).



        And it's the IFS splitting that takes care of separating the arguments (assuming the space character is in $IFS). That's similar to how $* was expanded in its predecessor the Mashey shell (itself based on the Thomson shell, while the Bourne shell was written from scratch).



        That explains why in the Bourne shell initially "$@" would expand to the empty string instead of nothing at all (you had to work around it with ${1+"$@"}) and why "$@" didn't work when $IFS didn't contain the space character.



        The intention was to be able to pass the list of arguments verbatim to another command, but that didn't work properly for the empty list or when $IFS didn't contain space.



        The Korn shell (on which the POSIX spec is based) changed that behaviour in a few ways:




        • IFS splitting is only done on the result of unquoted expansions (not on edit or file.txt in the example above)


        • $* and $@ are joined with the first character of $IFS or space when $IFS is empty except that for a quoted "$@", that joiner is unquoted like in the Bourne shell, and for a quoted "$*" when IFS is empty, the positional parameters are appended without separator.

        • it added support for arrays, and with ${array[@]} ${array[*]} reminiscent of Bourne's $* and $@ but starting at indice 0 instead of 1, and sparse (more like associative arrays) which means $@ cannot really be treated as a ksh array (compare with csh/rc/zsh/fish/yash where $argv/$* are normal array).


        • "$@" when $# is 0 now expands to nothing instead of the empty string, "$@" works when $IFS doesn't contain spaces except when IFS is empty. An unquoted $* without wildcards expands to one argument (where the positional parameters are joined with space) when $IFS is empty.


        ksh93 fixed the remaining few problems above. In ksh93, $* and $@ expands to the list of positional parameters, separated regardless of the value of $IFS, and then further split+globbed+brace-expanded in list contexts, $* joined with first byte (not character) of $IFS, "$@" in list contexts expands to the list of positional parameters, regardless of the value of $IFS. In non-list context, like in var=$@, $@ is joined with space regardless of the value of $IFS.



        bash's arrays are designed after the ksh ones. The differences are:




        • no brace-expand upon unquoted expansion

        • first character of $IFS instead of for byte

        • some corner case differences like the expansion of $* when non-quoted in non-list context when $IFS is empty.


        While the POSIX spec used to be pretty vague, it now more or less specifies the bash behaviour.



        It's different from normal arrays in ksh or bash in that:




        • Indices start at 1 instead of 0 (except in "${@:0}" which includes $0 (not a positional parameter, and in functions gives you the name of the function or not depending on the shell and how the function was defined)).

        • You can't elements individually

        • it's not sparse, you can't unset elements individually


        • shift can be used.


        In zsh or yash where arrays are normal arrays (not sparse, indices start at one like in all other shells but ksh/bash), $* is treated as a normal array. zsh has $argv as an alias for it (for compatibility with csh). $* is the same as $argv or ${argv[*]} (arguments joined with the first character of $IFS but still separated out in list contexts). "$@" like "${argv[@]}" or "${*[@]}"} undergoes the Korn-style special processing.






        share|improve this answer




























          6












          6








          6







          That started as a hack in the Bourne shell. In the Bourne shell, IFS word splitting was done (after tokenisation) on all words in list context (command line arguments or the words the for loops loop on). If you had:



          IFS=i var=file2.txt
          edit file.txt $var


          That second line would be tokenised in 3 words, $var would be expanded, and split+glob would be done on all three words, so you would end up running ed with t, f, le.txt, f, le2.txt as arguments.



          Quoting parts of that would prevent the split+glob. That Bourne shell initially remembered which characters were quoted by setting the 8th bit on them internally (that changed later when Unix became 8bit clean, but the shell still did something similar to remember which byte was quoted).



          Both $* and $@ were the concatenation of the positional parameters with space in-between. But there was a special processing of $@ when quoted. If $1 contained foo bar and $2 contained baz, "$@" would expand to:



          foo bar baz
          ^^^^^^^ ^^^


          Where the first space was quoted (had the 8th bit set) but not the second one (the one added in-between words).



          And it's the IFS splitting that takes care of separating the arguments (assuming the space character is in $IFS). That's similar to how $* was expanded in its predecessor the Mashey shell (itself based on the Thomson shell, while the Bourne shell was written from scratch).



          That explains why in the Bourne shell initially "$@" would expand to the empty string instead of nothing at all (you had to work around it with ${1+"$@"}) and why "$@" didn't work when $IFS didn't contain the space character.



          The intention was to be able to pass the list of arguments verbatim to another command, but that didn't work properly for the empty list or when $IFS didn't contain space.



          The Korn shell (on which the POSIX spec is based) changed that behaviour in a few ways:




          • IFS splitting is only done on the result of unquoted expansions (not on edit or file.txt in the example above)


          • $* and $@ are joined with the first character of $IFS or space when $IFS is empty except that for a quoted "$@", that joiner is unquoted like in the Bourne shell, and for a quoted "$*" when IFS is empty, the positional parameters are appended without separator.

          • it added support for arrays, and with ${array[@]} ${array[*]} reminiscent of Bourne's $* and $@ but starting at indice 0 instead of 1, and sparse (more like associative arrays) which means $@ cannot really be treated as a ksh array (compare with csh/rc/zsh/fish/yash where $argv/$* are normal array).


          • "$@" when $# is 0 now expands to nothing instead of the empty string, "$@" works when $IFS doesn't contain spaces except when IFS is empty. An unquoted $* without wildcards expands to one argument (where the positional parameters are joined with space) when $IFS is empty.


          ksh93 fixed the remaining few problems above. In ksh93, $* and $@ expands to the list of positional parameters, separated regardless of the value of $IFS, and then further split+globbed+brace-expanded in list contexts, $* joined with first byte (not character) of $IFS, "$@" in list contexts expands to the list of positional parameters, regardless of the value of $IFS. In non-list context, like in var=$@, $@ is joined with space regardless of the value of $IFS.



          bash's arrays are designed after the ksh ones. The differences are:




          • no brace-expand upon unquoted expansion

          • first character of $IFS instead of for byte

          • some corner case differences like the expansion of $* when non-quoted in non-list context when $IFS is empty.


          While the POSIX spec used to be pretty vague, it now more or less specifies the bash behaviour.



          It's different from normal arrays in ksh or bash in that:




          • Indices start at 1 instead of 0 (except in "${@:0}" which includes $0 (not a positional parameter, and in functions gives you the name of the function or not depending on the shell and how the function was defined)).

          • You can't elements individually

          • it's not sparse, you can't unset elements individually


          • shift can be used.


          In zsh or yash where arrays are normal arrays (not sparse, indices start at one like in all other shells but ksh/bash), $* is treated as a normal array. zsh has $argv as an alias for it (for compatibility with csh). $* is the same as $argv or ${argv[*]} (arguments joined with the first character of $IFS but still separated out in list contexts). "$@" like "${argv[@]}" or "${*[@]}"} undergoes the Korn-style special processing.






          share|improve this answer















          That started as a hack in the Bourne shell. In the Bourne shell, IFS word splitting was done (after tokenisation) on all words in list context (command line arguments or the words the for loops loop on). If you had:



          IFS=i var=file2.txt
          edit file.txt $var


          That second line would be tokenised in 3 words, $var would be expanded, and split+glob would be done on all three words, so you would end up running ed with t, f, le.txt, f, le2.txt as arguments.



          Quoting parts of that would prevent the split+glob. That Bourne shell initially remembered which characters were quoted by setting the 8th bit on them internally (that changed later when Unix became 8bit clean, but the shell still did something similar to remember which byte was quoted).



          Both $* and $@ were the concatenation of the positional parameters with space in-between. But there was a special processing of $@ when quoted. If $1 contained foo bar and $2 contained baz, "$@" would expand to:



          foo bar baz
          ^^^^^^^ ^^^


          Where the first space was quoted (had the 8th bit set) but not the second one (the one added in-between words).



          And it's the IFS splitting that takes care of separating the arguments (assuming the space character is in $IFS). That's similar to how $* was expanded in its predecessor the Mashey shell (itself based on the Thomson shell, while the Bourne shell was written from scratch).



          That explains why in the Bourne shell initially "$@" would expand to the empty string instead of nothing at all (you had to work around it with ${1+"$@"}) and why "$@" didn't work when $IFS didn't contain the space character.



          The intention was to be able to pass the list of arguments verbatim to another command, but that didn't work properly for the empty list or when $IFS didn't contain space.



          The Korn shell (on which the POSIX spec is based) changed that behaviour in a few ways:




          • IFS splitting is only done on the result of unquoted expansions (not on edit or file.txt in the example above)


          • $* and $@ are joined with the first character of $IFS or space when $IFS is empty except that for a quoted "$@", that joiner is unquoted like in the Bourne shell, and for a quoted "$*" when IFS is empty, the positional parameters are appended without separator.

          • it added support for arrays, and with ${array[@]} ${array[*]} reminiscent of Bourne's $* and $@ but starting at indice 0 instead of 1, and sparse (more like associative arrays) which means $@ cannot really be treated as a ksh array (compare with csh/rc/zsh/fish/yash where $argv/$* are normal array).


          • "$@" when $# is 0 now expands to nothing instead of the empty string, "$@" works when $IFS doesn't contain spaces except when IFS is empty. An unquoted $* without wildcards expands to one argument (where the positional parameters are joined with space) when $IFS is empty.


          ksh93 fixed the remaining few problems above. In ksh93, $* and $@ expands to the list of positional parameters, separated regardless of the value of $IFS, and then further split+globbed+brace-expanded in list contexts, $* joined with first byte (not character) of $IFS, "$@" in list contexts expands to the list of positional parameters, regardless of the value of $IFS. In non-list context, like in var=$@, $@ is joined with space regardless of the value of $IFS.



          bash's arrays are designed after the ksh ones. The differences are:




          • no brace-expand upon unquoted expansion

          • first character of $IFS instead of for byte

          • some corner case differences like the expansion of $* when non-quoted in non-list context when $IFS is empty.


          While the POSIX spec used to be pretty vague, it now more or less specifies the bash behaviour.



          It's different from normal arrays in ksh or bash in that:




          • Indices start at 1 instead of 0 (except in "${@:0}" which includes $0 (not a positional parameter, and in functions gives you the name of the function or not depending on the shell and how the function was defined)).

          • You can't elements individually

          • it's not sparse, you can't unset elements individually


          • shift can be used.


          In zsh or yash where arrays are normal arrays (not sparse, indices start at one like in all other shells but ksh/bash), $* is treated as a normal array. zsh has $argv as an alias for it (for compatibility with csh). $* is the same as $argv or ${argv[*]} (arguments joined with the first character of $IFS but still separated out in list contexts). "$@" like "${argv[@]}" or "${*[@]}"} undergoes the Korn-style special processing.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 4 hours ago

























          answered 4 hours ago









          Stéphane ChazelasStéphane Chazelas

          307k57581938




          307k57581938

























              1















              However, I don't know what data structure $@ is.




              It's a special parameter that expands to the values of the positional parameters...



              Taking the positional parameters as parts of $@, it has a number of distinct elements ($1, $2...), that can be accessed independently and are named by consecutive natural numbers. That would make it seem a lot like something called an array.



              The syntax is a bit weird, though, and even limited. There's no way to modify a single element of the array at a time, the whole thing has to be set at once. (You can use set -- "$@" foo to append a value, or set -- "${@:1:2}" foo "${@:3}" in some shells, to add a value in the middle, but you can't set the elements individually.)




              Why it behave differently with $* when including in double quote,




              Because they're defined to behave differently.




              Or in other words, I want to know how $@ stored in computer memory.




              That depends on the implementation, you'll have to look the source code of any particular shell you care about.




              Is it a string, a multi-line string or a array?




              An array, mostly. Though different from the ksh-style named arrays, since they
              can have arbitrary nonnegative integers as indexes, not just consecutive ones as with $@.



              It's not a single string, since it can be expanded to distinct elements, and calling the elements lines is also not right, since any regular variable, or one of the positional parameters (elements of $@) can also contain newlines.




              If it is a unique data type, is it possible to define a custom variable as an instance of this type?




              No.






              share|improve this answer




























                1















                However, I don't know what data structure $@ is.




                It's a special parameter that expands to the values of the positional parameters...



                Taking the positional parameters as parts of $@, it has a number of distinct elements ($1, $2...), that can be accessed independently and are named by consecutive natural numbers. That would make it seem a lot like something called an array.



                The syntax is a bit weird, though, and even limited. There's no way to modify a single element of the array at a time, the whole thing has to be set at once. (You can use set -- "$@" foo to append a value, or set -- "${@:1:2}" foo "${@:3}" in some shells, to add a value in the middle, but you can't set the elements individually.)




                Why it behave differently with $* when including in double quote,




                Because they're defined to behave differently.




                Or in other words, I want to know how $@ stored in computer memory.




                That depends on the implementation, you'll have to look the source code of any particular shell you care about.




                Is it a string, a multi-line string or a array?




                An array, mostly. Though different from the ksh-style named arrays, since they
                can have arbitrary nonnegative integers as indexes, not just consecutive ones as with $@.



                It's not a single string, since it can be expanded to distinct elements, and calling the elements lines is also not right, since any regular variable, or one of the positional parameters (elements of $@) can also contain newlines.




                If it is a unique data type, is it possible to define a custom variable as an instance of this type?




                No.






                share|improve this answer


























                  1












                  1








                  1








                  However, I don't know what data structure $@ is.




                  It's a special parameter that expands to the values of the positional parameters...



                  Taking the positional parameters as parts of $@, it has a number of distinct elements ($1, $2...), that can be accessed independently and are named by consecutive natural numbers. That would make it seem a lot like something called an array.



                  The syntax is a bit weird, though, and even limited. There's no way to modify a single element of the array at a time, the whole thing has to be set at once. (You can use set -- "$@" foo to append a value, or set -- "${@:1:2}" foo "${@:3}" in some shells, to add a value in the middle, but you can't set the elements individually.)




                  Why it behave differently with $* when including in double quote,




                  Because they're defined to behave differently.




                  Or in other words, I want to know how $@ stored in computer memory.




                  That depends on the implementation, you'll have to look the source code of any particular shell you care about.




                  Is it a string, a multi-line string or a array?




                  An array, mostly. Though different from the ksh-style named arrays, since they
                  can have arbitrary nonnegative integers as indexes, not just consecutive ones as with $@.



                  It's not a single string, since it can be expanded to distinct elements, and calling the elements lines is also not right, since any regular variable, or one of the positional parameters (elements of $@) can also contain newlines.




                  If it is a unique data type, is it possible to define a custom variable as an instance of this type?




                  No.






                  share|improve this answer














                  However, I don't know what data structure $@ is.




                  It's a special parameter that expands to the values of the positional parameters...



                  Taking the positional parameters as parts of $@, it has a number of distinct elements ($1, $2...), that can be accessed independently and are named by consecutive natural numbers. That would make it seem a lot like something called an array.



                  The syntax is a bit weird, though, and even limited. There's no way to modify a single element of the array at a time, the whole thing has to be set at once. (You can use set -- "$@" foo to append a value, or set -- "${@:1:2}" foo "${@:3}" in some shells, to add a value in the middle, but you can't set the elements individually.)




                  Why it behave differently with $* when including in double quote,




                  Because they're defined to behave differently.




                  Or in other words, I want to know how $@ stored in computer memory.




                  That depends on the implementation, you'll have to look the source code of any particular shell you care about.




                  Is it a string, a multi-line string or a array?




                  An array, mostly. Though different from the ksh-style named arrays, since they
                  can have arbitrary nonnegative integers as indexes, not just consecutive ones as with $@.



                  It's not a single string, since it can be expanded to distinct elements, and calling the elements lines is also not right, since any regular variable, or one of the positional parameters (elements of $@) can also contain newlines.




                  If it is a unique data type, is it possible to define a custom variable as an instance of this type?




                  No.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 4 hours ago









                  ilkkachuilkkachu

                  60k997169




                  60k997169






























                      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%2f503303%2fwhat-is-the-data-structure-of-in-shell%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

                      Benedict Cumberbatch Contingut Inicis Debut professional Premis Filmografia bàsica Premis i...

                      Monticle de plataforma Contingut Est de Nord Amèrica Interpretacions Altres cultures Vegeu...

                      Escacs Janus Enllaços externs Menú de navegacióEscacs JanusJanusschachBrainKing.comChessV