In bash, I parse a file line by line and extract the first and second field, like this:
$ cat myfile
a1 1
a2 2
a3 3
a4
$ while read -r first second; do echo first is $first second is $second; done < myfile
first is a1 second is 1
first is a2 second is 2
first is a3 second is 3
first is a4 second is
Now, I need to enclose the above command in bash -c
, since it will be executed through kubectl exec
. It doesn't work as expected and only evaluates what it has parsed in the last line:
$ bash -c "while read -r first second; do echo first is $first second is $second; done < myfile"
first is a4 second is
first is a4 second is
first is a4 second is
first is a4 second is
What's missing here?
Thanks!
CodePudding user response:
Your parameters expands in the parent shell, change your quotes or escape the parameter expansions:
$ bash -c 'while read -r first second; do echo first is $first second is $second; done < myfile'
or
$ bash -c "while read -r first second; do echo first is \$first second is \$second; done < myfile"
Note that you should almost always wrap your parameter expansions in double quotes:
echo "$a"
instead of
echo $a
To avoid word splitting and pathname expansion.
Conside the following example, in a POSIX shell:
a="hello *"; echo $a;
vs
a="hello *"; echo "$a";
So that would make your script end up looking like:
$ bash -c 'while read -r first second; do echo first is "$first" second is "$second"; done < myfile'
CodePudding user response:
And if you do not want to deal with intricacies of shell double-qouting, first define a function where you type your code manually where also shellcheck can help you typing proper code:
f() {
while IFS=' ' read -r first second; do
echo "first is $first second is $second";
done
}
then do:
printf "%q\n" "$(declare -f f); f"
$'f () \n{ \n while IFS=\' \' read -r first second; do\n echo "first is $first second is $second";\n done\n}; f'
declare
prints the function deifnition in a re-usable form, and after it we f
call the function. Then you can copy the output and re-use it in shell:
bash -c $'f () \n{ \n while IFS=\' \' read -r first second; do\n echo "first is $first second is $second";\n done\n}; f'
The $'...'
is specific to Bash C-quoting style, so use a different quoting function than printf %q
when needed.