How can I generate arguments to another command via command substitution
Following on from:
unexpected behaviour in shell command substitution
I have a command which can take a huge list of arguments, some of which can legitimately contain spaces (and probably other things)
I wrote a script which can generate those arguments for me, with quotes, but I must copy and paste the output e.g.
./somecommand
<output on stdout with quoting>
./othercommand some_args <output from above>
I tried to streamline this by simply doing
./othercommand $(./somecommand)
and ran into the unexpected behaviour mentioned in question above. The question is -- can command substitution be reliably used to generate the arguments to othercommand
given that some arguments require quoting and this cannot be changed?
shell
add a comment |
Following on from:
unexpected behaviour in shell command substitution
I have a command which can take a huge list of arguments, some of which can legitimately contain spaces (and probably other things)
I wrote a script which can generate those arguments for me, with quotes, but I must copy and paste the output e.g.
./somecommand
<output on stdout with quoting>
./othercommand some_args <output from above>
I tried to streamline this by simply doing
./othercommand $(./somecommand)
and ran into the unexpected behaviour mentioned in question above. The question is -- can command substitution be reliably used to generate the arguments to othercommand
given that some arguments require quoting and this cannot be changed?
shell
Depends on what you mean by "reliably". If you want next command take the output exactly as it appears on screen and apply shell rules to it, then maybeeval
could be used, but it's generally not recommended.xargs
is something to consider as well
– Sergiy Kolodyazhnyy
3 hours ago
I'd like (expect) the output fromsomecommand
to undergo regular shell parsing
– user1207217
3 hours ago
As I said in my answer, use some other character for field splitting (like:
)... assuming that character will reliably not be in the output.
– Olorin
3 hours ago
But that's not really right because it doesn't obey quoting rules, which is what this is about
– user1207217
3 hours ago
2
Could you post a real-world example? I mean, the actual output of the first command and how you want it to interact with the second command.
– nxnev
3 hours ago
add a comment |
Following on from:
unexpected behaviour in shell command substitution
I have a command which can take a huge list of arguments, some of which can legitimately contain spaces (and probably other things)
I wrote a script which can generate those arguments for me, with quotes, but I must copy and paste the output e.g.
./somecommand
<output on stdout with quoting>
./othercommand some_args <output from above>
I tried to streamline this by simply doing
./othercommand $(./somecommand)
and ran into the unexpected behaviour mentioned in question above. The question is -- can command substitution be reliably used to generate the arguments to othercommand
given that some arguments require quoting and this cannot be changed?
shell
Following on from:
unexpected behaviour in shell command substitution
I have a command which can take a huge list of arguments, some of which can legitimately contain spaces (and probably other things)
I wrote a script which can generate those arguments for me, with quotes, but I must copy and paste the output e.g.
./somecommand
<output on stdout with quoting>
./othercommand some_args <output from above>
I tried to streamline this by simply doing
./othercommand $(./somecommand)
and ran into the unexpected behaviour mentioned in question above. The question is -- can command substitution be reliably used to generate the arguments to othercommand
given that some arguments require quoting and this cannot be changed?
shell
shell
edited 1 hour ago
Rui F Ribeiro
39.6k1479132
39.6k1479132
asked 3 hours ago
user1207217user1207217
58137
58137
Depends on what you mean by "reliably". If you want next command take the output exactly as it appears on screen and apply shell rules to it, then maybeeval
could be used, but it's generally not recommended.xargs
is something to consider as well
– Sergiy Kolodyazhnyy
3 hours ago
I'd like (expect) the output fromsomecommand
to undergo regular shell parsing
– user1207217
3 hours ago
As I said in my answer, use some other character for field splitting (like:
)... assuming that character will reliably not be in the output.
– Olorin
3 hours ago
But that's not really right because it doesn't obey quoting rules, which is what this is about
– user1207217
3 hours ago
2
Could you post a real-world example? I mean, the actual output of the first command and how you want it to interact with the second command.
– nxnev
3 hours ago
add a comment |
Depends on what you mean by "reliably". If you want next command take the output exactly as it appears on screen and apply shell rules to it, then maybeeval
could be used, but it's generally not recommended.xargs
is something to consider as well
– Sergiy Kolodyazhnyy
3 hours ago
I'd like (expect) the output fromsomecommand
to undergo regular shell parsing
– user1207217
3 hours ago
As I said in my answer, use some other character for field splitting (like:
)... assuming that character will reliably not be in the output.
– Olorin
3 hours ago
But that's not really right because it doesn't obey quoting rules, which is what this is about
– user1207217
3 hours ago
2
Could you post a real-world example? I mean, the actual output of the first command and how you want it to interact with the second command.
– nxnev
3 hours ago
Depends on what you mean by "reliably". If you want next command take the output exactly as it appears on screen and apply shell rules to it, then maybe
eval
could be used, but it's generally not recommended. xargs
is something to consider as well– Sergiy Kolodyazhnyy
3 hours ago
Depends on what you mean by "reliably". If you want next command take the output exactly as it appears on screen and apply shell rules to it, then maybe
eval
could be used, but it's generally not recommended. xargs
is something to consider as well– Sergiy Kolodyazhnyy
3 hours ago
I'd like (expect) the output from
somecommand
to undergo regular shell parsing– user1207217
3 hours ago
I'd like (expect) the output from
somecommand
to undergo regular shell parsing– user1207217
3 hours ago
As I said in my answer, use some other character for field splitting (like
:
)... assuming that character will reliably not be in the output.– Olorin
3 hours ago
As I said in my answer, use some other character for field splitting (like
:
)... assuming that character will reliably not be in the output.– Olorin
3 hours ago
But that's not really right because it doesn't obey quoting rules, which is what this is about
– user1207217
3 hours ago
But that's not really right because it doesn't obey quoting rules, which is what this is about
– user1207217
3 hours ago
2
2
Could you post a real-world example? I mean, the actual output of the first command and how you want it to interact with the second command.
– nxnev
3 hours ago
Could you post a real-world example? I mean, the actual output of the first command and how you want it to interact with the second command.
– nxnev
3 hours ago
add a comment |
3 Answers
3
active
oldest
votes
I wrote a script which can generate those arguments for me, with quotes
If the output is properly quoted for the shell, and you trust the output, then you could run eval
on it.
Assuming you have a shell that supports arrays, it would be best to use one to store the arguments you get.
If ./gen_args.sh
produces output like 'foo bar' '*' asdf
, then we could run eval "args=( $(./gen_args.sh) )"
to populate an array called args
with the results. That would be the three elements foo bar
, *
, asdf
.
We can use "${args[@]}"
as usual to expand the array elements individually:
$ eval "args=( $(./gen_args.sh) )"
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
However, eval
will happily run any shell substitutions, so $HOME
in the output would expand to your home directory, and a command substitution would actually run a command in the shell running eval
. An output of "$(date >&2)"
would create a single empty array element and print the current date on stdout. This is a concern if gen_args.sh
gets the data from some untrusted source, like another host over the network, file names created by other users. The output could include arbitrary commands. (If get_args.sh
itself was malicious, it wouldn't need to output anything, it could just run the malicious commands directly.)
An alternative to shell quoting, which is hard to parse without eval, would be to use some other character as separator in the output of your script. You'd need to pick one that is not needed in the actual arguments.
Let's choose #
, and have the script output foo bar#*#asdf
. Now we can use unquoted command expansion to split the output of the command to the arguments.
$ IFS='#' # split on '#' signs
$ set -f # disable globbing
$ args=( $( ./gen_args3.sh ) ) # assign the values to the array
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
You'll need to set IFS
back later if you depend on word splitting elsewhere in the script (unset IFS
should work to make it the default), and also use set +f
if you want to use globbing later.
If you're not using Bash or some other shell that has arrays, you could use the positional parameters for that. Replace args=( $(...) )
with set -- $(./gen_args.sh)
and use "$@"
instead of "${args[@]}"
then.
Best of both worlds!
– Olorin
2 hours ago
add a comment |
If the somecommand
output is in reliably good shell syntax, you can use eval
:
$ eval sh test.sh $(echo '"hello " "hi and bye"')
hello
hi and bye
But you have to be sure that the output has valid quoting and such, otherwise you might end up running commands outside the script as well:
$ cat test.sh
for var in "$@"
do
echo "|$var|"
done
$ ls
bar baz test.sh
$ eval sh test.sh $(echo '"hello " "hi and bye"; echo rm *')
|hello |
|hi and bye|
rm bar baz test.sh
Note that echo rm bar baz test.sh
wasn't passed to the script (because of the ;
) and was run as a separate command. I added the |
around $var
to highlight this.
Generally, unless you can completely trust the output of somecommand
, it's not possible to reliably use its output to build a command string.
add a comment |
The issue is that once your somecommand
script outputs the options, it's really just text and at the mercy of the shell's standard parsing (affected by whatever $IFS
happens to be and what shell options are in effect).
Instead of using somecommand
to output the options, it would be easier, safer, and more robust to use it to call othercommand
.
In bash
, ksh
or zsh
, you could then easily use an array to hold the individual options inside somecommand
like so:
options=( "hi there" "nice weather" "here's a star" "*" )
options+=( "bonus bumblebee!" ) # add additional option
Then call othercommand
(still within somecommand
):
othercommand "${options[@]}"
The expansion of "${options[@]}"
would ensure that each element of the options
array is individually quoted and presented to othercommand
as separate arguments.
In /bin/sh
, use $@
to hold the options:
set -- "hi there" "nice weather" "here's a star" "*"
set -- "$@" "bonus bumblebee!" # add additional option
othercommand "$@"
(set
is the command used for setting the positional parameters $1
, $2
, $3
etc. These are what makes up the array $@
in a standard POSIX shell. The initial --
is to signal to set
that there are no options given, only arguments. The --
is really only needed if the first value happens to be something starting with -
).
Note that it's the double quotes around $@
and ${options[@]}
that ensures that the elements are not individually word-splitted (and filename globbed).
could you explainset --
?
– user1207217
2 hours ago
@user1207217 Added explanation to answer.
– Kusalananda
2 hours ago
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%2f495769%2fhow-can-i-generate-arguments-to-another-command-via-command-substitution%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
I wrote a script which can generate those arguments for me, with quotes
If the output is properly quoted for the shell, and you trust the output, then you could run eval
on it.
Assuming you have a shell that supports arrays, it would be best to use one to store the arguments you get.
If ./gen_args.sh
produces output like 'foo bar' '*' asdf
, then we could run eval "args=( $(./gen_args.sh) )"
to populate an array called args
with the results. That would be the three elements foo bar
, *
, asdf
.
We can use "${args[@]}"
as usual to expand the array elements individually:
$ eval "args=( $(./gen_args.sh) )"
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
However, eval
will happily run any shell substitutions, so $HOME
in the output would expand to your home directory, and a command substitution would actually run a command in the shell running eval
. An output of "$(date >&2)"
would create a single empty array element and print the current date on stdout. This is a concern if gen_args.sh
gets the data from some untrusted source, like another host over the network, file names created by other users. The output could include arbitrary commands. (If get_args.sh
itself was malicious, it wouldn't need to output anything, it could just run the malicious commands directly.)
An alternative to shell quoting, which is hard to parse without eval, would be to use some other character as separator in the output of your script. You'd need to pick one that is not needed in the actual arguments.
Let's choose #
, and have the script output foo bar#*#asdf
. Now we can use unquoted command expansion to split the output of the command to the arguments.
$ IFS='#' # split on '#' signs
$ set -f # disable globbing
$ args=( $( ./gen_args3.sh ) ) # assign the values to the array
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
You'll need to set IFS
back later if you depend on word splitting elsewhere in the script (unset IFS
should work to make it the default), and also use set +f
if you want to use globbing later.
If you're not using Bash or some other shell that has arrays, you could use the positional parameters for that. Replace args=( $(...) )
with set -- $(./gen_args.sh)
and use "$@"
instead of "${args[@]}"
then.
Best of both worlds!
– Olorin
2 hours ago
add a comment |
I wrote a script which can generate those arguments for me, with quotes
If the output is properly quoted for the shell, and you trust the output, then you could run eval
on it.
Assuming you have a shell that supports arrays, it would be best to use one to store the arguments you get.
If ./gen_args.sh
produces output like 'foo bar' '*' asdf
, then we could run eval "args=( $(./gen_args.sh) )"
to populate an array called args
with the results. That would be the three elements foo bar
, *
, asdf
.
We can use "${args[@]}"
as usual to expand the array elements individually:
$ eval "args=( $(./gen_args.sh) )"
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
However, eval
will happily run any shell substitutions, so $HOME
in the output would expand to your home directory, and a command substitution would actually run a command in the shell running eval
. An output of "$(date >&2)"
would create a single empty array element and print the current date on stdout. This is a concern if gen_args.sh
gets the data from some untrusted source, like another host over the network, file names created by other users. The output could include arbitrary commands. (If get_args.sh
itself was malicious, it wouldn't need to output anything, it could just run the malicious commands directly.)
An alternative to shell quoting, which is hard to parse without eval, would be to use some other character as separator in the output of your script. You'd need to pick one that is not needed in the actual arguments.
Let's choose #
, and have the script output foo bar#*#asdf
. Now we can use unquoted command expansion to split the output of the command to the arguments.
$ IFS='#' # split on '#' signs
$ set -f # disable globbing
$ args=( $( ./gen_args3.sh ) ) # assign the values to the array
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
You'll need to set IFS
back later if you depend on word splitting elsewhere in the script (unset IFS
should work to make it the default), and also use set +f
if you want to use globbing later.
If you're not using Bash or some other shell that has arrays, you could use the positional parameters for that. Replace args=( $(...) )
with set -- $(./gen_args.sh)
and use "$@"
instead of "${args[@]}"
then.
Best of both worlds!
– Olorin
2 hours ago
add a comment |
I wrote a script which can generate those arguments for me, with quotes
If the output is properly quoted for the shell, and you trust the output, then you could run eval
on it.
Assuming you have a shell that supports arrays, it would be best to use one to store the arguments you get.
If ./gen_args.sh
produces output like 'foo bar' '*' asdf
, then we could run eval "args=( $(./gen_args.sh) )"
to populate an array called args
with the results. That would be the three elements foo bar
, *
, asdf
.
We can use "${args[@]}"
as usual to expand the array elements individually:
$ eval "args=( $(./gen_args.sh) )"
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
However, eval
will happily run any shell substitutions, so $HOME
in the output would expand to your home directory, and a command substitution would actually run a command in the shell running eval
. An output of "$(date >&2)"
would create a single empty array element and print the current date on stdout. This is a concern if gen_args.sh
gets the data from some untrusted source, like another host over the network, file names created by other users. The output could include arbitrary commands. (If get_args.sh
itself was malicious, it wouldn't need to output anything, it could just run the malicious commands directly.)
An alternative to shell quoting, which is hard to parse without eval, would be to use some other character as separator in the output of your script. You'd need to pick one that is not needed in the actual arguments.
Let's choose #
, and have the script output foo bar#*#asdf
. Now we can use unquoted command expansion to split the output of the command to the arguments.
$ IFS='#' # split on '#' signs
$ set -f # disable globbing
$ args=( $( ./gen_args3.sh ) ) # assign the values to the array
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
You'll need to set IFS
back later if you depend on word splitting elsewhere in the script (unset IFS
should work to make it the default), and also use set +f
if you want to use globbing later.
If you're not using Bash or some other shell that has arrays, you could use the positional parameters for that. Replace args=( $(...) )
with set -- $(./gen_args.sh)
and use "$@"
instead of "${args[@]}"
then.
I wrote a script which can generate those arguments for me, with quotes
If the output is properly quoted for the shell, and you trust the output, then you could run eval
on it.
Assuming you have a shell that supports arrays, it would be best to use one to store the arguments you get.
If ./gen_args.sh
produces output like 'foo bar' '*' asdf
, then we could run eval "args=( $(./gen_args.sh) )"
to populate an array called args
with the results. That would be the three elements foo bar
, *
, asdf
.
We can use "${args[@]}"
as usual to expand the array elements individually:
$ eval "args=( $(./gen_args.sh) )"
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
However, eval
will happily run any shell substitutions, so $HOME
in the output would expand to your home directory, and a command substitution would actually run a command in the shell running eval
. An output of "$(date >&2)"
would create a single empty array element and print the current date on stdout. This is a concern if gen_args.sh
gets the data from some untrusted source, like another host over the network, file names created by other users. The output could include arbitrary commands. (If get_args.sh
itself was malicious, it wouldn't need to output anything, it could just run the malicious commands directly.)
An alternative to shell quoting, which is hard to parse without eval, would be to use some other character as separator in the output of your script. You'd need to pick one that is not needed in the actual arguments.
Let's choose #
, and have the script output foo bar#*#asdf
. Now we can use unquoted command expansion to split the output of the command to the arguments.
$ IFS='#' # split on '#' signs
$ set -f # disable globbing
$ args=( $( ./gen_args3.sh ) ) # assign the values to the array
$ for var in "${args[@]}"; do printf ":%s:n" "$var"; done
:foo bar:
:*:
:asdf:
You'll need to set IFS
back later if you depend on word splitting elsewhere in the script (unset IFS
should work to make it the default), and also use set +f
if you want to use globbing later.
If you're not using Bash or some other shell that has arrays, you could use the positional parameters for that. Replace args=( $(...) )
with set -- $(./gen_args.sh)
and use "$@"
instead of "${args[@]}"
then.
edited 1 hour ago
answered 2 hours ago
ilkkachuilkkachu
56.8k785157
56.8k785157
Best of both worlds!
– Olorin
2 hours ago
add a comment |
Best of both worlds!
– Olorin
2 hours ago
Best of both worlds!
– Olorin
2 hours ago
Best of both worlds!
– Olorin
2 hours ago
add a comment |
If the somecommand
output is in reliably good shell syntax, you can use eval
:
$ eval sh test.sh $(echo '"hello " "hi and bye"')
hello
hi and bye
But you have to be sure that the output has valid quoting and such, otherwise you might end up running commands outside the script as well:
$ cat test.sh
for var in "$@"
do
echo "|$var|"
done
$ ls
bar baz test.sh
$ eval sh test.sh $(echo '"hello " "hi and bye"; echo rm *')
|hello |
|hi and bye|
rm bar baz test.sh
Note that echo rm bar baz test.sh
wasn't passed to the script (because of the ;
) and was run as a separate command. I added the |
around $var
to highlight this.
Generally, unless you can completely trust the output of somecommand
, it's not possible to reliably use its output to build a command string.
add a comment |
If the somecommand
output is in reliably good shell syntax, you can use eval
:
$ eval sh test.sh $(echo '"hello " "hi and bye"')
hello
hi and bye
But you have to be sure that the output has valid quoting and such, otherwise you might end up running commands outside the script as well:
$ cat test.sh
for var in "$@"
do
echo "|$var|"
done
$ ls
bar baz test.sh
$ eval sh test.sh $(echo '"hello " "hi and bye"; echo rm *')
|hello |
|hi and bye|
rm bar baz test.sh
Note that echo rm bar baz test.sh
wasn't passed to the script (because of the ;
) and was run as a separate command. I added the |
around $var
to highlight this.
Generally, unless you can completely trust the output of somecommand
, it's not possible to reliably use its output to build a command string.
add a comment |
If the somecommand
output is in reliably good shell syntax, you can use eval
:
$ eval sh test.sh $(echo '"hello " "hi and bye"')
hello
hi and bye
But you have to be sure that the output has valid quoting and such, otherwise you might end up running commands outside the script as well:
$ cat test.sh
for var in "$@"
do
echo "|$var|"
done
$ ls
bar baz test.sh
$ eval sh test.sh $(echo '"hello " "hi and bye"; echo rm *')
|hello |
|hi and bye|
rm bar baz test.sh
Note that echo rm bar baz test.sh
wasn't passed to the script (because of the ;
) and was run as a separate command. I added the |
around $var
to highlight this.
Generally, unless you can completely trust the output of somecommand
, it's not possible to reliably use its output to build a command string.
If the somecommand
output is in reliably good shell syntax, you can use eval
:
$ eval sh test.sh $(echo '"hello " "hi and bye"')
hello
hi and bye
But you have to be sure that the output has valid quoting and such, otherwise you might end up running commands outside the script as well:
$ cat test.sh
for var in "$@"
do
echo "|$var|"
done
$ ls
bar baz test.sh
$ eval sh test.sh $(echo '"hello " "hi and bye"; echo rm *')
|hello |
|hi and bye|
rm bar baz test.sh
Note that echo rm bar baz test.sh
wasn't passed to the script (because of the ;
) and was run as a separate command. I added the |
around $var
to highlight this.
Generally, unless you can completely trust the output of somecommand
, it's not possible to reliably use its output to build a command string.
answered 2 hours ago
OlorinOlorin
1,779313
1,779313
add a comment |
add a comment |
The issue is that once your somecommand
script outputs the options, it's really just text and at the mercy of the shell's standard parsing (affected by whatever $IFS
happens to be and what shell options are in effect).
Instead of using somecommand
to output the options, it would be easier, safer, and more robust to use it to call othercommand
.
In bash
, ksh
or zsh
, you could then easily use an array to hold the individual options inside somecommand
like so:
options=( "hi there" "nice weather" "here's a star" "*" )
options+=( "bonus bumblebee!" ) # add additional option
Then call othercommand
(still within somecommand
):
othercommand "${options[@]}"
The expansion of "${options[@]}"
would ensure that each element of the options
array is individually quoted and presented to othercommand
as separate arguments.
In /bin/sh
, use $@
to hold the options:
set -- "hi there" "nice weather" "here's a star" "*"
set -- "$@" "bonus bumblebee!" # add additional option
othercommand "$@"
(set
is the command used for setting the positional parameters $1
, $2
, $3
etc. These are what makes up the array $@
in a standard POSIX shell. The initial --
is to signal to set
that there are no options given, only arguments. The --
is really only needed if the first value happens to be something starting with -
).
Note that it's the double quotes around $@
and ${options[@]}
that ensures that the elements are not individually word-splitted (and filename globbed).
could you explainset --
?
– user1207217
2 hours ago
@user1207217 Added explanation to answer.
– Kusalananda
2 hours ago
add a comment |
The issue is that once your somecommand
script outputs the options, it's really just text and at the mercy of the shell's standard parsing (affected by whatever $IFS
happens to be and what shell options are in effect).
Instead of using somecommand
to output the options, it would be easier, safer, and more robust to use it to call othercommand
.
In bash
, ksh
or zsh
, you could then easily use an array to hold the individual options inside somecommand
like so:
options=( "hi there" "nice weather" "here's a star" "*" )
options+=( "bonus bumblebee!" ) # add additional option
Then call othercommand
(still within somecommand
):
othercommand "${options[@]}"
The expansion of "${options[@]}"
would ensure that each element of the options
array is individually quoted and presented to othercommand
as separate arguments.
In /bin/sh
, use $@
to hold the options:
set -- "hi there" "nice weather" "here's a star" "*"
set -- "$@" "bonus bumblebee!" # add additional option
othercommand "$@"
(set
is the command used for setting the positional parameters $1
, $2
, $3
etc. These are what makes up the array $@
in a standard POSIX shell. The initial --
is to signal to set
that there are no options given, only arguments. The --
is really only needed if the first value happens to be something starting with -
).
Note that it's the double quotes around $@
and ${options[@]}
that ensures that the elements are not individually word-splitted (and filename globbed).
could you explainset --
?
– user1207217
2 hours ago
@user1207217 Added explanation to answer.
– Kusalananda
2 hours ago
add a comment |
The issue is that once your somecommand
script outputs the options, it's really just text and at the mercy of the shell's standard parsing (affected by whatever $IFS
happens to be and what shell options are in effect).
Instead of using somecommand
to output the options, it would be easier, safer, and more robust to use it to call othercommand
.
In bash
, ksh
or zsh
, you could then easily use an array to hold the individual options inside somecommand
like so:
options=( "hi there" "nice weather" "here's a star" "*" )
options+=( "bonus bumblebee!" ) # add additional option
Then call othercommand
(still within somecommand
):
othercommand "${options[@]}"
The expansion of "${options[@]}"
would ensure that each element of the options
array is individually quoted and presented to othercommand
as separate arguments.
In /bin/sh
, use $@
to hold the options:
set -- "hi there" "nice weather" "here's a star" "*"
set -- "$@" "bonus bumblebee!" # add additional option
othercommand "$@"
(set
is the command used for setting the positional parameters $1
, $2
, $3
etc. These are what makes up the array $@
in a standard POSIX shell. The initial --
is to signal to set
that there are no options given, only arguments. The --
is really only needed if the first value happens to be something starting with -
).
Note that it's the double quotes around $@
and ${options[@]}
that ensures that the elements are not individually word-splitted (and filename globbed).
The issue is that once your somecommand
script outputs the options, it's really just text and at the mercy of the shell's standard parsing (affected by whatever $IFS
happens to be and what shell options are in effect).
Instead of using somecommand
to output the options, it would be easier, safer, and more robust to use it to call othercommand
.
In bash
, ksh
or zsh
, you could then easily use an array to hold the individual options inside somecommand
like so:
options=( "hi there" "nice weather" "here's a star" "*" )
options+=( "bonus bumblebee!" ) # add additional option
Then call othercommand
(still within somecommand
):
othercommand "${options[@]}"
The expansion of "${options[@]}"
would ensure that each element of the options
array is individually quoted and presented to othercommand
as separate arguments.
In /bin/sh
, use $@
to hold the options:
set -- "hi there" "nice weather" "here's a star" "*"
set -- "$@" "bonus bumblebee!" # add additional option
othercommand "$@"
(set
is the command used for setting the positional parameters $1
, $2
, $3
etc. These are what makes up the array $@
in a standard POSIX shell. The initial --
is to signal to set
that there are no options given, only arguments. The --
is really only needed if the first value happens to be something starting with -
).
Note that it's the double quotes around $@
and ${options[@]}
that ensures that the elements are not individually word-splitted (and filename globbed).
edited 1 hour ago
answered 3 hours ago
KusalanandaKusalananda
125k16236389
125k16236389
could you explainset --
?
– user1207217
2 hours ago
@user1207217 Added explanation to answer.
– Kusalananda
2 hours ago
add a comment |
could you explainset --
?
– user1207217
2 hours ago
@user1207217 Added explanation to answer.
– Kusalananda
2 hours ago
could you explain
set --
?– user1207217
2 hours ago
could you explain
set --
?– user1207217
2 hours ago
@user1207217 Added explanation to answer.
– Kusalananda
2 hours ago
@user1207217 Added explanation to answer.
– Kusalananda
2 hours ago
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%2f495769%2fhow-can-i-generate-arguments-to-another-command-via-command-substitution%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
Depends on what you mean by "reliably". If you want next command take the output exactly as it appears on screen and apply shell rules to it, then maybe
eval
could be used, but it's generally not recommended.xargs
is something to consider as well– Sergiy Kolodyazhnyy
3 hours ago
I'd like (expect) the output from
somecommand
to undergo regular shell parsing– user1207217
3 hours ago
As I said in my answer, use some other character for field splitting (like
:
)... assuming that character will reliably not be in the output.– Olorin
3 hours ago
But that's not really right because it doesn't obey quoting rules, which is what this is about
– user1207217
3 hours ago
2
Could you post a real-world example? I mean, the actual output of the first command and how you want it to interact with the second command.
– nxnev
3 hours ago