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)
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
add a comment |
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
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 withprintf '%sn' "$@"
andprintf '%sn' "$*"
. Theecho
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 doa=(a b c); echo "${a[@]}"
in the shell, or@a=(1, 2, 4); print @a;
in Perl, ora=[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
add a comment |
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
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
bash shell
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 withprintf '%sn' "$@"
andprintf '%sn' "$*"
. Theecho
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 doa=(a b c); echo "${a[@]}"
in the shell, or@a=(1, 2, 4); print @a;
in Perl, ora=[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
add a comment |
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 withprintf '%sn' "$@"
andprintf '%sn' "$*"
. Theecho
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 doa=(a b c); echo "${a[@]}"
in the shell, or@a=(1, 2, 4); print @a;
in Perl, ora=[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
add a comment |
2 Answers
2
active
oldest
votes
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
orfile.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"$*"
whenIFS
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 withcsh
/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 whenIFS
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.
add a comment |
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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
orfile.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"$*"
whenIFS
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 withcsh
/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 whenIFS
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.
add a comment |
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
orfile.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"$*"
whenIFS
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 withcsh
/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 whenIFS
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.
add a comment |
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
orfile.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"$*"
whenIFS
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 withcsh
/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 whenIFS
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.
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
orfile.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"$*"
whenIFS
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 withcsh
/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 whenIFS
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.
edited 4 hours ago
answered 4 hours ago
Stéphane ChazelasStéphane Chazelas
307k57581938
307k57581938
add a comment |
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered 4 hours ago
ilkkachuilkkachu
60k997169
60k997169
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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' "$@"
andprintf '%sn' "$*"
. Theecho
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, ora=[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