Using shell 'printf' where the format string is in a variable and doesn't have a fixed number of field placeholders?
Clash Royale CLAN TAG#URR8PPP
up vote
0
down vote
favorite
I am writing a shell function which makes an external API call via cURL (the external API syntax isn't under my control). I've approached it like this (simplified):
#!/bin/sh
template_get_entry='get_entry:%s'
template_set_entry='set_entry:%s=%s'
curlheaders='-H stuff'
curluri="https://www.domain.com:1234/api.php"
# make an API call to get entry "foo"
call_api "$template_get_entry" "foo"
# make an API call to set entry "foo" to "bar"
call_api "$template_set_entry" "foo" "bar"
call_api()
apicmd="$( printf "$1" "$2" "$3" )"
result="$( eval "/usr/local/bin/curl" "$curlheaders" "-d" "$apicmd" "$curluri" )"
retcode="$?"
.....stuff.....
There are 2 problems with this code.
First, the number of args is variable. If the line defining apicmd
is called with less than the maximal number of args, printf interprets any excess commands as extra instances of printing the format string, to be appended. I can't see the correct way to work around this.
Second, because I've used eval, this creates a knockon problem with eval, in that retcode will surely pick up the return code from eval
and not from curl
, and I don't know the right way to prevent/fix that.
How should I do something like this, which needs a variable number of args?
shell-script function variable-substitution printf return-status
add a comment |Â
up vote
0
down vote
favorite
I am writing a shell function which makes an external API call via cURL (the external API syntax isn't under my control). I've approached it like this (simplified):
#!/bin/sh
template_get_entry='get_entry:%s'
template_set_entry='set_entry:%s=%s'
curlheaders='-H stuff'
curluri="https://www.domain.com:1234/api.php"
# make an API call to get entry "foo"
call_api "$template_get_entry" "foo"
# make an API call to set entry "foo" to "bar"
call_api "$template_set_entry" "foo" "bar"
call_api()
apicmd="$( printf "$1" "$2" "$3" )"
result="$( eval "/usr/local/bin/curl" "$curlheaders" "-d" "$apicmd" "$curluri" )"
retcode="$?"
.....stuff.....
There are 2 problems with this code.
First, the number of args is variable. If the line defining apicmd
is called with less than the maximal number of args, printf interprets any excess commands as extra instances of printing the format string, to be appended. I can't see the correct way to work around this.
Second, because I've used eval, this creates a knockon problem with eval, in that retcode will surely pick up the return code from eval
and not from curl
, and I don't know the right way to prevent/fix that.
How should I do something like this, which needs a variable number of args?
shell-script function variable-substitution printf return-status
1
I don't really see why you useeval
...
â Kusalananda
Aug 7 at 7:32
I don't know another way or a more sensible way to do variable-argument-count substitution, and run the result as a command (yet). I might, by the end of this question.
â Stilez
Aug 7 at 10:03
You don't seem to have a variable number of arguments in the call tocurl
though.
â Kusalananda
Aug 7 at 10:06
I don't. Thecurl
arg string is templated, though, and the args used to build it are passed as the functio's 2nd+ args, substituted in the functions 1st arg, and the resulting string is used as the curl args. That's where the variable args list kicks in.
â Stilez
Aug 7 at 10:59
It's still just a simple string when you do the call tocurl
though.
â Kusalananda
Aug 7 at 11:03
add a comment |Â
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I am writing a shell function which makes an external API call via cURL (the external API syntax isn't under my control). I've approached it like this (simplified):
#!/bin/sh
template_get_entry='get_entry:%s'
template_set_entry='set_entry:%s=%s'
curlheaders='-H stuff'
curluri="https://www.domain.com:1234/api.php"
# make an API call to get entry "foo"
call_api "$template_get_entry" "foo"
# make an API call to set entry "foo" to "bar"
call_api "$template_set_entry" "foo" "bar"
call_api()
apicmd="$( printf "$1" "$2" "$3" )"
result="$( eval "/usr/local/bin/curl" "$curlheaders" "-d" "$apicmd" "$curluri" )"
retcode="$?"
.....stuff.....
There are 2 problems with this code.
First, the number of args is variable. If the line defining apicmd
is called with less than the maximal number of args, printf interprets any excess commands as extra instances of printing the format string, to be appended. I can't see the correct way to work around this.
Second, because I've used eval, this creates a knockon problem with eval, in that retcode will surely pick up the return code from eval
and not from curl
, and I don't know the right way to prevent/fix that.
How should I do something like this, which needs a variable number of args?
shell-script function variable-substitution printf return-status
I am writing a shell function which makes an external API call via cURL (the external API syntax isn't under my control). I've approached it like this (simplified):
#!/bin/sh
template_get_entry='get_entry:%s'
template_set_entry='set_entry:%s=%s'
curlheaders='-H stuff'
curluri="https://www.domain.com:1234/api.php"
# make an API call to get entry "foo"
call_api "$template_get_entry" "foo"
# make an API call to set entry "foo" to "bar"
call_api "$template_set_entry" "foo" "bar"
call_api()
apicmd="$( printf "$1" "$2" "$3" )"
result="$( eval "/usr/local/bin/curl" "$curlheaders" "-d" "$apicmd" "$curluri" )"
retcode="$?"
.....stuff.....
There are 2 problems with this code.
First, the number of args is variable. If the line defining apicmd
is called with less than the maximal number of args, printf interprets any excess commands as extra instances of printing the format string, to be appended. I can't see the correct way to work around this.
Second, because I've used eval, this creates a knockon problem with eval, in that retcode will surely pick up the return code from eval
and not from curl
, and I don't know the right way to prevent/fix that.
How should I do something like this, which needs a variable number of args?
shell-script function variable-substitution printf return-status
shell-script function variable-substitution printf return-status
asked Aug 7 at 7:17
Stilez
441211
441211
1
I don't really see why you useeval
...
â Kusalananda
Aug 7 at 7:32
I don't know another way or a more sensible way to do variable-argument-count substitution, and run the result as a command (yet). I might, by the end of this question.
â Stilez
Aug 7 at 10:03
You don't seem to have a variable number of arguments in the call tocurl
though.
â Kusalananda
Aug 7 at 10:06
I don't. Thecurl
arg string is templated, though, and the args used to build it are passed as the functio's 2nd+ args, substituted in the functions 1st arg, and the resulting string is used as the curl args. That's where the variable args list kicks in.
â Stilez
Aug 7 at 10:59
It's still just a simple string when you do the call tocurl
though.
â Kusalananda
Aug 7 at 11:03
add a comment |Â
1
I don't really see why you useeval
...
â Kusalananda
Aug 7 at 7:32
I don't know another way or a more sensible way to do variable-argument-count substitution, and run the result as a command (yet). I might, by the end of this question.
â Stilez
Aug 7 at 10:03
You don't seem to have a variable number of arguments in the call tocurl
though.
â Kusalananda
Aug 7 at 10:06
I don't. Thecurl
arg string is templated, though, and the args used to build it are passed as the functio's 2nd+ args, substituted in the functions 1st arg, and the resulting string is used as the curl args. That's where the variable args list kicks in.
â Stilez
Aug 7 at 10:59
It's still just a simple string when you do the call tocurl
though.
â Kusalananda
Aug 7 at 11:03
1
1
I don't really see why you use
eval
...â Kusalananda
Aug 7 at 7:32
I don't really see why you use
eval
...â Kusalananda
Aug 7 at 7:32
I don't know another way or a more sensible way to do variable-argument-count substitution, and run the result as a command (yet). I might, by the end of this question.
â Stilez
Aug 7 at 10:03
I don't know another way or a more sensible way to do variable-argument-count substitution, and run the result as a command (yet). I might, by the end of this question.
â Stilez
Aug 7 at 10:03
You don't seem to have a variable number of arguments in the call to
curl
though.â Kusalananda
Aug 7 at 10:06
You don't seem to have a variable number of arguments in the call to
curl
though.â Kusalananda
Aug 7 at 10:06
I don't. The
curl
arg string is templated, though, and the args used to build it are passed as the functio's 2nd+ args, substituted in the functions 1st arg, and the resulting string is used as the curl args. That's where the variable args list kicks in.â Stilez
Aug 7 at 10:59
I don't. The
curl
arg string is templated, though, and the args used to build it are passed as the functio's 2nd+ args, substituted in the functions 1st arg, and the resulting string is used as the curl args. That's where the variable args list kicks in.â Stilez
Aug 7 at 10:59
It's still just a simple string when you do the call to
curl
though.â Kusalananda
Aug 7 at 11:03
It's still just a simple string when you do the call to
curl
though.â Kusalananda
Aug 7 at 11:03
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
1
down vote
accepted
You could try to fill the format strings with zero length specifiers up to the maximum expected parameter count:
template_get_entry='get_entry:%s %0.0s'
Worked, and keeps code short. Note that if I didn't want to add null (zero length) field placeholders or didn't know the max args, I would have tried Kusalananda's solution.
â Stilez
Aug 8 at 11:13
add a comment |Â
up vote
1
down vote
What you could do is to get the format string argument, shift it off the argument list and then use $@
:
call_api ()
fmt=$1
shift
apicmd=$( printf "$fmt" "$@" )
# ...
This sounds like it would work; however I ended up using RudiC's solution because it keeps the code short and if it worked would almost certainly be guaranteed portable, whereas shell substitutions and builtins might not always be. But I appreciate this answer which would have been my #2 choice to try, if it hadn't. Also this would be better code if I wasn't sure of a maximum number of args, or didn't want to pad out the template strings with extra null fields.
â Stilez
Aug 8 at 11:12
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
You could try to fill the format strings with zero length specifiers up to the maximum expected parameter count:
template_get_entry='get_entry:%s %0.0s'
Worked, and keeps code short. Note that if I didn't want to add null (zero length) field placeholders or didn't know the max args, I would have tried Kusalananda's solution.
â Stilez
Aug 8 at 11:13
add a comment |Â
up vote
1
down vote
accepted
You could try to fill the format strings with zero length specifiers up to the maximum expected parameter count:
template_get_entry='get_entry:%s %0.0s'
Worked, and keeps code short. Note that if I didn't want to add null (zero length) field placeholders or didn't know the max args, I would have tried Kusalananda's solution.
â Stilez
Aug 8 at 11:13
add a comment |Â
up vote
1
down vote
accepted
up vote
1
down vote
accepted
You could try to fill the format strings with zero length specifiers up to the maximum expected parameter count:
template_get_entry='get_entry:%s %0.0s'
You could try to fill the format strings with zero length specifiers up to the maximum expected parameter count:
template_get_entry='get_entry:%s %0.0s'
answered Aug 7 at 7:47
RudiC
1,1837
1,1837
Worked, and keeps code short. Note that if I didn't want to add null (zero length) field placeholders or didn't know the max args, I would have tried Kusalananda's solution.
â Stilez
Aug 8 at 11:13
add a comment |Â
Worked, and keeps code short. Note that if I didn't want to add null (zero length) field placeholders or didn't know the max args, I would have tried Kusalananda's solution.
â Stilez
Aug 8 at 11:13
Worked, and keeps code short. Note that if I didn't want to add null (zero length) field placeholders or didn't know the max args, I would have tried Kusalananda's solution.
â Stilez
Aug 8 at 11:13
Worked, and keeps code short. Note that if I didn't want to add null (zero length) field placeholders or didn't know the max args, I would have tried Kusalananda's solution.
â Stilez
Aug 8 at 11:13
add a comment |Â
up vote
1
down vote
What you could do is to get the format string argument, shift it off the argument list and then use $@
:
call_api ()
fmt=$1
shift
apicmd=$( printf "$fmt" "$@" )
# ...
This sounds like it would work; however I ended up using RudiC's solution because it keeps the code short and if it worked would almost certainly be guaranteed portable, whereas shell substitutions and builtins might not always be. But I appreciate this answer which would have been my #2 choice to try, if it hadn't. Also this would be better code if I wasn't sure of a maximum number of args, or didn't want to pad out the template strings with extra null fields.
â Stilez
Aug 8 at 11:12
add a comment |Â
up vote
1
down vote
What you could do is to get the format string argument, shift it off the argument list and then use $@
:
call_api ()
fmt=$1
shift
apicmd=$( printf "$fmt" "$@" )
# ...
This sounds like it would work; however I ended up using RudiC's solution because it keeps the code short and if it worked would almost certainly be guaranteed portable, whereas shell substitutions and builtins might not always be. But I appreciate this answer which would have been my #2 choice to try, if it hadn't. Also this would be better code if I wasn't sure of a maximum number of args, or didn't want to pad out the template strings with extra null fields.
â Stilez
Aug 8 at 11:12
add a comment |Â
up vote
1
down vote
up vote
1
down vote
What you could do is to get the format string argument, shift it off the argument list and then use $@
:
call_api ()
fmt=$1
shift
apicmd=$( printf "$fmt" "$@" )
# ...
What you could do is to get the format string argument, shift it off the argument list and then use $@
:
call_api ()
fmt=$1
shift
apicmd=$( printf "$fmt" "$@" )
# ...
answered Aug 7 at 7:30
Kusalananda
106k14209327
106k14209327
This sounds like it would work; however I ended up using RudiC's solution because it keeps the code short and if it worked would almost certainly be guaranteed portable, whereas shell substitutions and builtins might not always be. But I appreciate this answer which would have been my #2 choice to try, if it hadn't. Also this would be better code if I wasn't sure of a maximum number of args, or didn't want to pad out the template strings with extra null fields.
â Stilez
Aug 8 at 11:12
add a comment |Â
This sounds like it would work; however I ended up using RudiC's solution because it keeps the code short and if it worked would almost certainly be guaranteed portable, whereas shell substitutions and builtins might not always be. But I appreciate this answer which would have been my #2 choice to try, if it hadn't. Also this would be better code if I wasn't sure of a maximum number of args, or didn't want to pad out the template strings with extra null fields.
â Stilez
Aug 8 at 11:12
This sounds like it would work; however I ended up using RudiC's solution because it keeps the code short and if it worked would almost certainly be guaranteed portable, whereas shell substitutions and builtins might not always be. But I appreciate this answer which would have been my #2 choice to try, if it hadn't. Also this would be better code if I wasn't sure of a maximum number of args, or didn't want to pad out the template strings with extra null fields.
â Stilez
Aug 8 at 11:12
This sounds like it would work; however I ended up using RudiC's solution because it keeps the code short and if it worked would almost certainly be guaranteed portable, whereas shell substitutions and builtins might not always be. But I appreciate this answer which would have been my #2 choice to try, if it hadn't. Also this would be better code if I wasn't sure of a maximum number of args, or didn't want to pad out the template strings with extra null fields.
â Stilez
Aug 8 at 11:12
add a comment |Â
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
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f460980%2fusing-shell-printf-where-the-format-string-is-in-a-variable-and-doesnt-have-a%23new-answer', 'question_page');
);
Post as a guest
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
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
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
1
I don't really see why you use
eval
...â Kusalananda
Aug 7 at 7:32
I don't know another way or a more sensible way to do variable-argument-count substitution, and run the result as a command (yet). I might, by the end of this question.
â Stilez
Aug 7 at 10:03
You don't seem to have a variable number of arguments in the call to
curl
though.â Kusalananda
Aug 7 at 10:06
I don't. The
curl
arg string is templated, though, and the args used to build it are passed as the functio's 2nd+ args, substituted in the functions 1st arg, and the resulting string is used as the curl args. That's where the variable args list kicks in.â Stilez
Aug 7 at 10:59
It's still just a simple string when you do the call to
curl
though.â Kusalananda
Aug 7 at 11:03