I'm quite new to linux shell scripting and have a question:
1.) why does the command
test1="leafpad" && coproc exec "$test1"
work in bash (commandline, GNU bash 4.4.12 on a debian derivate linux), but the command
test1="coproc" && exec "$test1" leafpad
does not? Error messages: bash: exec: coproc: Not found.
whereas
coproc leafpad
does work as expected.
How this command must be correct quouted to make it work? I've tried already
test1=`coproc` && exec "$test1" leafpad
test1='coproc' && exec "$test1" leafpad
test1="'coproc'" && exec "$test1" leafpad
test1=`coproc` && exec '$test1' leafpad
test1=`coproc` && exec `$test1` leafpad
test1="coproc" && exec $test1 leafpad
test1=`coproc` && exec $test1 leafpad
and some more variations, but none of them works.
2.) This was the test on commandline only. But what I rather need is to do this within a script: So I'm sure there are to be done some additional quotations or masquerading of special characters.
Background: I have to execute a command, containing many arguments, some of them replaced by variables. Think of something like yad with all its possible arguments in a couple of lines, but let's create an easier example:
my_codeset="437"
my_line="20"
my_filename="somthing.txt"
if [ $value == 0 ]; then my_tabwidth='--tab-width=10'; else my_tabwidth=""; fi # set tabs or not
leafpad --codeset="$my_codeset" "$my_tabwidth" --jump="$my_line" "$my_filename"
wherein the variables given are subject of change, as a function of user interaction before.
Now this complete command (which is about 6 lines of code in original), needs to be executed in two variants: one time headed by coproc, and another time not, as a function of an conditional branch.
so what I want is:
if [ $something == 1 ]; then copr_this="coproc"; else copr_this=""; fi
exec '$copr_this' <mycommand, with all its quoted arguments>
instead of
if [ something == 0]; then
lengthy command here
else
coproc lengthy command here, exactly repeated.
fi
I tried to manage it the other way around already, which was to put the complete lengthy command in a variable, and execute it in an conditional branch:
my_command=`lengthy command with some arguments $arg1 $arg2 ...`
if...
exec "$my_command"
else
coproc exec "$my_command"
fi
which stopped with error message "not found" also. Different ways of quoting didn't solve it, but produced different error messages only. I didn't manage to find out the correct quoting for this task. How shold this qouting read correctly?
For sure I could repeat the 6 lines of command in the code, but I'm quite sure this could be done more convenient.
As stated in the beginning: The indirect command execution works on commandline (and within script also), as long as coproc isn't involved. I cant't get it to work with coproc.
Any help and hints appreciated.
Update after first answer from @Socowi:
Thank you for your comprehensive and quick answer, Socowi. You are obviously right about coproc
not beeing a command. So I understand now why my attempts had to fail. The exec
command was added only during my experiments. I had started without this, but after having no success I thought it could help. It was an act of desperation merely. The backward quotes in the line my_command=`lengthy command with some arguments $arg1 $arg2 ...`
were a typo, there should have been normal quotes, as you pointed out, since I intended to execute the command within the if
of course. I'll probably head for the way you directed me to, using function {...}
within script. But having experimented on this question in the meantime, I came to an astonishing solution: Astonishing for me, because of the difference between coproc
not beeing a command and leafpad
with its binary beeing a command. So it should be clear that test1='coproc' && test2='leafpad' && "$test1 $test2"
will fail with error message bash: coproc leafpad: command not found.
, which is true. But now: why would test1='coproc' && test2='leafpad' && /bin/bash -c "$test1 $test2"
do the job, starting leafpad, allowing to enter further commands in bash parallel, just as if I had entered leafpad &
only? But this time executing both, the builtin (or keyword?) and the command, from a variable, which was refused when trying to enter it directly in the first bash instance. What is true for the first instance of bash should be true for the second also, or do I have a false perspective? Why does it work this way? Does the -c
option do anything else than to execute the command?
Quoting is not the problem here. There are two other problems:
exec
and coproc
and builtins vs. binariestest1="leafpad" && coproc exec "$test1"
is the same as coproc exec leafpad
.
test1="coproc" && exec "$test1" leafpad
is the same as exec coproc leafpad
.
The order makes a difference: coproc exec
vs. exec coproc
. The latter does not work because exec
replaces the current shell with the specified program. However, coproc
is a builtin command. There is no coproc
binary on your system. You can run it only from inside bash
. Therfore exec
fails.
In your script ...
my_command=`lengthy command`
if ...; then
exec "$my_command"
else
coproc exec "$my_command"
fi
... you did not store lengthy command
inside the variable, but you ran that command and stored its output (v=`cmd`
is the same as v=$(cmd)
) before the if
. Then inside the if, you tried to execute the output of the command as another command.
To store the command as a string and execute it later you could use my_command="lengthy command"; $my_command
(note the intentionally missing quotes). However, bash offers far better ways to store commands. Instead of strings use arrays or functions. Here we use a function:
my_command() {
exec lengthy command
}
if ...; then
coproc my_command
else
my_command
fi
coproc exec
?That being said, I really wonder about the combination of coproc
and exec
. To me it seems coproc exec cmd
ignores the exec
part and is the same as coproc cmd
. If exec
acted normally here, the current shell would be replaced, you would loose the COPROC
array and therefore wouldn't need the coproc
. Either way, using both at the same time seems strange. Are you really sure you need that exec
there? If so, I'd be happy to hear the reasons.