Why do we need "bash -c"? What'd happen in a world without "bash -c"?

Joined
Apr 16, 2023
Messages
155
Reaction score
19
Credits
1,515
Before you ask me to RTFM, Quoting from the manpages:
-c string If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.
But it's not very clear. I've read almost all stackoverflow and stackexchange questions about it and they've just complicated it for me.
I want to know a real life use case of it. And please upvote the correct answer so that I can know it.
Less:
bash -c 'echo $SHELL $HOME $USER'
env -i bash -c 'echo $SHELL $HOME $USER'


This is an example scenario where bash -c has been used in my tutorial that I'm following. I want to know its deep meaning.
 



Apparently, it will remove any "/' marks, then assign any options to positional parameters.
Likely most useful with complex bash scripting. :)
 
-c If the -c option is present, then commands are read from the
first non-option argument command_string. If there are argu‐
ments after the command_string, the first argument is as‐
signed to $0 and any remaining arguments are assigned to the
positional parameters. The assignment to $0 sets the name of
the shell, which is used in warning and error messages.

The only real advantage to this I can see, is that whatever variable is returned as $0 from
the first command, automatically gets passed on as an argument variable.
 
You could run this script as is, but the echo $0 doesn't do anything.
In fact you could leave the echo $0 out, and it would be the same.

#!/usr/bin/bash
echo "This doesn't do much".
echo $0

But now we save this file as myscript.sh
and give it executable permissions. ( i.e. chmod 755 )
But this time we call the script a little differently. Instead of
simply typing ./myscript.sh, we do this..

bash -c ./myscript.sh

Notice this time, the echo $0 gives some output. In this case it gives
the output of the name of the script. Why does it show us that?
Because, the command we ran was bash -c ( argument )
If we didn't put a command or file after the bash -c, it would fail and say it needs an option or argument.

So then, what was the argument variable we used? ./myscript.sh
Since $0 is the value of the argument we used, that's what gets returned.

This would be handy in a loop running a lot of commands for example.
You know which script was the one that returned the value you were looking for.
 
The -c option to bash executes the commands from a string and if there are quotes, that which is inside the quotes which is seen as a command and options unit.

Firstly here is a run of what happens in the example in post #5 on this machine here:
Code:
[flip@flop ~/]$ echo $0
bash

Showing the created script:
Code:
[flip@flop ~/]$ cat myscript.sh
#!/usr/bin/bash
echo "This doesn't do much"
echo $0

Making the script executable:
Code:
chmod 755 myscript

Running the script in 3 ways:
Code:
[flip@flop ~/]$ ./myscript.sh
This doesn't do much
./myscript.sh

[flip@flop ~/]$ bash ./myscript.sh
This doesn't do much
./myscript.sh

[flip@flop ~/]$ bash -c ./myscript.sh
This doesn't do much
./myscript.sh
On this system, the -c makes no difference to the output.

Here is another example where the -c makes a difference using the command ls as the example command:

Code:
[flip@flop ~/]$ bash ls
/usr/bin/ls: /usr/bin/ls: cannot execute binary file

bash lets the user know why it can't execute ls.

However, introducing the -c option, enables the command ls to run:
Code:
[flip@flop ~/]$ bash -c ls
abc                  cons     gost         shut
alpineDocs           ffff     hhh          sofaudio
alpineSoundMain.txt  forkk    myscript.sh  webserv
alpineSound.txt      forkk.c  networkServ  xxxprob
<snip>

Again, using the -c option, but adding options to the ls command, only outputs the ls command, and appears to ignore the -al options:
Code:
[flip@flop ~/]$ bash -c ls -al
abc                  cons     gost         shut
alpineDocs           ffff     hhh          sofaudio
alpineSoundMain.txt  forkk    myscript.sh  webserv
<snip>

However, when the ls -al command is quoted, the expected result is output, that is, the command and it's options are seen as a unit of command and options and run:

Code:
[flip@flop ~/]$ bash -c "ls -al"
total 1796
drwxr-xr-x  2 flip flip   4096 Jun 11 08:24 .
drwxr-xr-x 99 flip flip  12288 Jun 11 08:33 ..
-rw-r--r--  1 flip flip   2089 May 21 09:32 abc
-rw-r--r--  1 flip flip    378 Jun  3 15:55 alpineDocs
-rw-r--r--  1 flip flip   7717 May 20 18:15 alpineSoundMain.txt
<snip>
Quoting doesn't work with bash alone:

Code:
[flip@flop ~/]$ bash "ls -al"
bash: ls -al: No such file or directory
 
Last edited:
You could run this script as is, but the echo $0 doesn't do anything.
In fact you could leave the echo $0 out, and it would be the same.

#!/usr/bin/bash
echo "This doesn't do much".
echo $0

But now we save this file as myscript.sh
and give it executable permissions. ( i.e. chmod 755 )
But this time we call the script a little differently. Instead of
simply typing ./myscript.sh, we do this..

bash -c ./myscript.sh

Notice this time, the echo $0 gives some output. In this case it gives
the output of the name of the script. Why does it show us that?
Because, the command we ran was bash -c ( argument )
If we didn't put a command or file after the bash -c, it would fail and say it needs an option or argument.

So then, what was the argument variable we used? ./myscript.sh
Since $0 is the value of the argument we used, that's what gets returned.

This would be handy in a loop running a lot of commands for example.
You know which script was the one that returned the value you were looking for.
Code:
[root@worker-2 ~]# ./myscript.sh
This doesn't do much.
./myscript.sh
[root@worker-2 ~]# bash -c ./myscript.sh
This doesn't do much.
./myscript.sh
I'm getting the same output in both cases. Why?
 
Super duper explanation.
The -c option to bash executes the commands from a string and if there are quotes, that which is inside the quotes which is seen as a command and options unit.

Firstly here is a run of what happens in the example in post #5 on this machine here:
Code:
[flip@flop ~/]$ echo $0
bash

Showing the created script:
Code:
[flip@flop ~/]$ cat myscript.sh
#!/usr/bin/bash
echo "This doesn't do much"
echo $0

Making the script executable:
Code:
chmod 755 myscript

Running the script in 3 ways:
Code:
[flip@flop ~/]$ ./myscript.sh
This doesn't do much
./myscript.sh

[flip@flop ~/]$ bash ./myscript.sh
This doesn't do much
./myscript.sh

[flip@flop ~/]$ bash -c ./myscript.sh
This doesn't do much
./myscript.sh
On this system, the -c makes no difference to the output.

Here is another example where the -c makes a difference using the command ls as the example command:

Code:
[flip@flop ~/]$ bash ls
/usr/bin/ls: /usr/bin/ls: cannot execute binary file

bash lets the user know why it can't execute ls.

However, introducing the -c option, enables the command ls to run:
Code:
[flip@flop ~/]$ bash -c ls
abc                  cons     gost         shut
alpineDocs           ffff     hhh          sofaudio
alpineSoundMain.txt  forkk    myscript.sh  webserv
alpineSound.txt      forkk.c  networkServ  xxxprob
<snip>

Again, using the -c option, but adding options to the ls command, only outputs the ls command, and appears to ignore the -al options:
Code:
[flip@flop ~/]$ bash -c ls -al
abc                  cons     gost         shut
alpineDocs           ffff     hhh          sofaudio
alpineSoundMain.txt  forkk    myscript.sh  webserv
<snip>

However, when the ls -al command is quoted, the expected result is output, that is, the command and it's options are seen as a unit of command and options and run:

Code:
[flip@flop ~/]$ bash -c "ls -al"
total 1796
drwxr-xr-x  2 flip flip   4096 Jun 11 08:24 .
drwxr-xr-x 99 flip flip  12288 Jun 11 08:33 ..
-rw-r--r--  1 flip flip   2089 May 21 09:32 abc
-rw-r--r--  1 flip flip    378 Jun  3 15:55 alpineDocs
-rw-r--r--  1 flip flip   7717 May 20 18:15 alpineSoundMain.txt
<snip>
Quoting doesn't work with bash alone:

Code:
[flip@flop ~/]$ bash "ls -al"
bash: ls -al: No such file or directory
Could you add $0 parameters to your explanation example. Thanks a tooon.
 
Super duper explanation.

Could you add $0 parameters to your explanation example. Thanks a tooon.

The built-in variables in bash that hold command line arguments are called "positional parameters" and they have the names, 1, 2, 3 etc. Their values are expressed in bash with $, hence $1 is the first positional parameter, meaning the first argument to the command, $2 denotes the second etc. The positional parameter $0 denotes the name of the script, that is, the name of the command which has run all the other positional parameters, if there are any.

Hence echo $0 outputs "bash" because it was the bash command that ran to produce that output:
Code:
[flip@flop ~/]$  echo $0
bash

echo is a bash builtin.

If the user asks bash to run echo, as in the following, bash looks for a bash script in a file to run, doesn't find one, and so fails with the shown message:

Code:
[flip@flop ~/]$ bash 'echo $0'
bash: echo $0: No such file or directory

If however, you use the -c option, bash interprets the quoted element as a string, which is itself a command that can run, so it runs, and in this case outputs "bash" for the same reason as above, since it was bash that produced what denotes $0, which is a bash builtin.

Code:
[flip@flop ~/]$ bash -c 'echo $0'
bash
 
Before you ask me to RTFM, Quoting from the manpages:

But it's not very clear. I've read almost all stackoverflow and stackexchange questions about it and they've just complicated it for me.
I want to know a real life use case of it. And please upvote the correct answer so that I can know it.
Less:
bash -c 'echo $SHELL $HOME $USER'
env -i bash -c 'echo $SHELL $HOME $USER'


This is an example scenario where bash -c has been used in my tutorial that I'm following. I want to know its deep meaning.
Hi there,
Some simple commands:
/bash://echo
/bash/echo -c
/bash//debian
/bash//debian -c
kind regards.
 
Hi there,
Some simple commands:
/bash://echo
/bash/echo -c
/bash//debian
/bash//debian -c
kind regards.
Some responses:
Code:
[flip@flop ~]$ /bash://echo
bash: /bash://echo: No such file or directory
[flip@flop ~]$ /bash/echo -c
bash: /bash/echo: No such file or directory
[flip@flop ~]$ /bash//debian 
bash: /bash//debian: No such file or directory
[flip@flop ~]$ /bash//debian -c
bash: /bash//debian: No such file or directory
It wasn't clear to me what point you were making.
 
No such point just some simple commands. The String all important as it is.
Kind regards.
 
No such point just some simple commands. The String all important as it is.
Kind regards.
Did you perhaps not read post #11 to see that the proposed commands in post #10 were in fact not executable commands? Perhaps there was something else you had in mind, but nevertheless it was still unclear to me.
 


Top