Working nested quotes in Bash?
-
Is anyone a Bash expert, trying to run a command with nested single and double quotes is driving me insane.
I have this command, it runs fine on a line by itself in bash.bashrc:
runuser -l pi -c "sudo -E ionice -c 1 -n 0 nice -n -18 `which gst-launch-1.0` -v curlhttpsrc location=http://192.168.158.106/dash/test_dash/index.mpd name=source ! application/dash+xml ! dashdemux name=dd0 ! qtdemux name=d1 ! h264parse ! omxh264dec ! glupload ! glcolorconvert ! glcolorscale ! capsfilter caps='video/x-raw(memory:GLMemory),width=800,height=480' ! glimagesink"
I want to stick it in this loop as the variable
run_command
:until $run_command; do echo "Server '$run_command' crashed with exit code $?. Respawning.." >&2 sleep 10 done
I though I could simply use the shell to build a string and get the quotes correct but I cannot get it working:
printf -v gstreamer_command '%q ' sudo -E ionice -c 1 -n 0 nice -n -18 `which gst-launch-1.0` -v curlhttpsrc location=http://192.168.158.106/dash/test_dash/index.mpd name=source ! application/dash+xml ! dashdemux name=dd0 ! qtdemux name=d1 ! h264parse ! omxh264dec ! glupload ! glcolorconvert ! glcolorscale ! capsfilter caps='video/x-raw(memory:GLMemory),width=800,height=480' ! glimagesink printf -v run_command '%q ' runuser -l pi -c $gstreamer_command
But I get this instead:
Server 'runuser -l pi -c sudo -E ionice -c 1 -n 0 nice -n -18 /usr/local/bin/gst -launch-1.0 -v curlhttpsrc location=http://192.168.158.106/dash/test_dash/index. mpd name=source \! application/dash+xml \! dashdemux name=dd0 \! qtdemux name=d1 \! h264parse \! omxh264dec \! glupload \! glcolorconvert \! glc olorscale \! capsfilter caps=video/x-raw\(memory:GLMemory\)\,width=800\ ,height=480 \! glimagesink ' crashed with exit code 1. Respawning..
runuser: invalid option -- 'E'I can see the problem, runuser thinks the entire command for it to run is simply
sudo
and the rest is arguments, but I'm not sure why it's happening :/
-
Try Python.
-
@gąska said in Working nested quotes in Bash?:
Try Python.
Unfortunately that means learning Python. I'll take a look.
-
@cursorkeys learning entirety of Python will take you less time than this single piece of Bash.
-
Would a function work?
Edit: I just noticed that the inner loop prints the command. Some answers here might help with that.
run_command() { runuser -l pi -c "sudo -E ionice -c 1 -n 0 nice -n -18 `which gst-launch-1.0` -v curlhttpsrc location=http://192.168.158.106/dash/test_dash/index.mpd name=source ! application/dash+xml ! dashdemux name=dd0 ! qtdemux name=d1 ! h264parse ! omxh264dec ! glupload ! glcolorconvert ! glcolorscale ! capsfilter caps='video/x-raw(memory:GLMemory),width=800,height=480' ! glimagesink" } until run_command; do echo "Server '$run_command' crashed with exit code $?. Respawning.." >&2 sleep 10 done
-
@cursorkeys Is using
printf
a requirement? I.e., the following seems to work:gstreamer_command="sudo -E ionice -c 1 -n 0 nice -n -18 `which gst-launch-1.0` -v curlhttpsrc location=http://192.168.158.106/dash/test_dash/index.mpd name=source ! application/dash+xml ! dashdemux name=dd0 ! qtdemux name=d1 ! h264parse ! omxh264dec ! glupload ! glcolorconvert ! glcolorscale ! capsfilter caps='video/x-raw(memory:GLMemory),width=800,height=480' ! glimagesink" run_command="runuser -l pi -c \"$gstreamer_command\"" ... until eval $run_command; do ... done
(Actually, you can probably do it with printf+eval too...)
-
Building quoted command lines, while possible, is hard to do properly. Better keep the command line as an array. It's possible, since you're using
bash
:declare -a run_command=(runuser -l pi -c "sudo -E ionice -c 1 -n 0 nice -n -18 `which gst-launch-1.0` -v curlhttpsrc location=http://192.168.158.106/dash/test_dash/index.mpd name=source ! application/dash+xml ! dashdemux name=dd0 ! qtdemux name=d1 ! h264parse ! omxh264dec ! glupload ! glcolorconvert ! glcolorscale ! capsfilter caps='video/x-raw(memory:GLMemory),width=800,height=480' ! glimagesink") # ... until "${run_command[@]}"; do echo "Server '${run_command[*]}' crashed with exit code $?. Respawning.." >&2 sleep 10 done
${array[@]}
is like$@
, but for bash arrays instead of command like arguments: it expands each element to a separate word, and the outside quotes ensure that each word is quoted.${array[*]}
is, on the other hand, like$*
: it glues the array elements together when quoted.Yes, the syntax looks crazy.
-
@mzh said in Working nested quotes in Bash?:
Would a function work?
Edit: I just noticed that the inner loop prints the command. Some answers here might help with that.
run_command() { runuser -l pi -c "sudo -E ionice -c 1 -n 0 nice -n -18 `which gst-launch-1.0` -v curlhttpsrc location=http://192.168.158.106/dash/test_dash/index.mpd name=source ! application/dash+xml ! dashdemux name=dd0 ! qtdemux name=d1 ! h264parse ! omxh264dec ! glupload ! glcolorconvert ! glcolorscale ! capsfilter caps='video/x-raw(memory:GLMemory),width=800,height=480' ! glimagesink" } until run_command; do echo "Server '$run_command' crashed with exit code $?. Respawning.." >&2 sleep 10 done
@cvi said in Working nested quotes in Bash?:
@cursorkeys Is using
printf
a requirement? I.e., the following seems to work:gstreamer_command="sudo -E ionice -c 1 -n 0 nice -n -18 `which gst-launch-1.0` -v curlhttpsrc location=http://192.168.158.106/dash/test_dash/index.mpd name=source ! application/dash+xml ! dashdemux name=dd0 ! qtdemux name=d1 ! h264parse ! omxh264dec ! glupload ! glcolorconvert ! glcolorscale ! capsfilter caps='video/x-raw(memory:GLMemory),width=800,height=480' ! glimagesink" run_command="runuser -l pi -c \"$gstreamer_command\"" ... until eval $run_command; do ... done
(Actually, you can probably do it with printf+eval too...)
Both of these work great, thank you!
I'll look into Python as well when I get more time, seems quite neat.
-
Try PowerShell.