mirror of
https://github.com/flokoe/bash-hackers-wiki.git
synced 2024-11-25 15:53:41 +01:00
94 lines
2.0 KiB
Markdown
94 lines
2.0 KiB
Markdown
---
|
|
tags:
|
|
- arguments
|
|
- quoting
|
|
- escape
|
|
- quote
|
|
- wrapper
|
|
- generate
|
|
---
|
|
|
|
# Generate code with own arguments properly quoted
|
|
|
|
There are situations where Bash code needs to generate Bash code. A
|
|
script that writes out another script the user or cron may start, for
|
|
example.
|
|
|
|
The general issue is easy, just write out text to the file.
|
|
|
|
A specific detail of it is tricky: If the generated script needs to call
|
|
a command using the arguments the first original script got, you have
|
|
problem in writing out the correct code.
|
|
|
|
I.e. if you run your generator script like
|
|
|
|
./myscript "give me 'some' water"
|
|
|
|
then this script should generate code that looks like
|
|
|
|
echo give me 'some' water"
|
|
|
|
you need correct escapes or quotes to not generate shell special
|
|
characters out of normal text (like embedded dollar signs `$`).
|
|
|
|
**<u>Solution:</u>**
|
|
|
|
A loop over the own arguments that writes out properly quoted/escaped
|
|
code to the generated script file
|
|
|
|
There are two (maybe more) easy options:
|
|
|
|
- writing out singlequoted strings and handle the embedded
|
|
singlequotes
|
|
- the [printf command](../commands/builtin/printf.md) knows the `%q` format
|
|
specification, which will print a string (like `%s` does), but with
|
|
all shell special characters escaped
|
|
|
|
## Using singlequoted string
|
|
|
|
#!/bin/bash
|
|
|
|
# first option:
|
|
# generate singlequoted strings out of your own arguments and handle embedded singlequotes
|
|
# here to call 'echo' in the generated script
|
|
|
|
{
|
|
printf "#!/bin/bash\n\n"
|
|
printf "echo "
|
|
for arg; do
|
|
arg=${arg/\'/\'\\\'\'}
|
|
printf "'%s' " "${arg}"
|
|
done
|
|
|
|
printf "\n"
|
|
} >s2
|
|
|
|
The generated script will look like:
|
|
|
|
#!/bin/bash
|
|
|
|
echo 'fir$t' 'seco "ond"' 'thir'\''d'
|
|
|
|
## Using printf
|
|
|
|
The second method is easier, though more or less Bash-only (due to the
|
|
`%q` in printf):
|
|
|
|
#!/bin/bash
|
|
|
|
{
|
|
printf "#!/bin/bash\n\n"
|
|
printf "echo "
|
|
for arg; do
|
|
printf '%q ' "$arg"
|
|
done
|
|
|
|
printf "\n"
|
|
} >s2
|
|
|
|
The generated script will look like:
|
|
|
|
#!/bin/bash
|
|
|
|
echo fir\$t seco\ \"ond\" thir\'d
|