What is the sh -c command?
I discovered the sh -c
command. I found it before I posted here but I can't find any posts from Google that explain it, so I would like to know what it is and what its complete syntax is.
Solution 1:
sh
calls the program sh
as interpreter and the -c
flag means execute the following command as interpreted by this program.
In Ubuntu, sh
is usually symlinked to /bin/dash
, meaning that if you execute a command with sh -c
the dash shell will be used to execute the command instead of bash. The shell called with sh
depends on the symlink - you can find out with readlink -e $(which sh)
. You should use sh -c
when you want to execute a command specifically with that shell instead of bash.
You can use this syntax (the -c
flag) with other interpreters too. One classic use of it (pointed out by @edwinksl is to get around the problem of redirection not working with sudo (here you could use bash -c
or sh -c
)
sudo sh -c 'echo "foo" > /home/bar'
will write the file bar
containing the text foo
to /home/
, while sudo echo "foo" > /home/bar
fails as explained very well here
It's important to use 'single quotes' around the command string, otherwise the current shell will try to expand it before it's passed to the interpreter you called. For example with python
:
$ python3 -c print (35/7)
bash: syntax error near unexpected token `('
$ python3 -c 'print (35/7)'
5.0
Solution 2:
The -c
argument is:
Read commands from the command_string operand instead of from the standard input. Special parameter 0 will be set from the command_name operand and the positional parameters ($1, $2, etc.) set from the remaining argument operands.
Other details of the sh
arugments can be found by running:
$ man sh
An example of using a string as an argument is:
$ sh -c "echo This is a test string"
This is a more detailed sh -c
example. It will download a document from Google Drive and open it up for editing on the desktop:
$ sh -c "wget 'https://docs.google.com/document/u/0/d/1jcBtdlMx0f4BhCmAmnIViIy4WN4oRevWFRzse-P00j0/export?format=docx' -O test.docx && xdg-open test.docx 2>/dev/null"
Solution 3:
sh -c
spawns a non-login, non-interactive session of sh
(dash
in Ubuntu).
The command following that will be run in that shell session, it will be treated as argument (positional parameter) 0 (ARGV0
), and the remaining portion as the argument to that command (ARGV0
), starting from 1 (ARGV1
, ARGV2
, ...).
You can also use typical shell features allowed to run in this kind of session e.g. command separation using ;
to use multiple commands, command grouping using {}
, spawn another subshell with ()
, and so on. Usage of these can slightly change the argument definitions/examples mentioned earlier.
Just to note, the features that are specific to interactive shells only (by default), e.g. history expansion, source
-ing of ~/.bashrc
and /etc/bash.bashrc
etc will not be available in this session as it is non-interactive. You can simulate an interactive sessions behavior (almost), by using the -i
option:
sh -ic ...
Similarly, the features that are specific to login shells only (by default) e.g. source
-ing of ~/.profile
(given ~/.bash_profile
and ~/.bash_login
do not exist) and /etc/profile
will not be done as the shell is a non-login shell. You can simulate login-shells behavior using the -l
option:
sh -lc ...
To simulate both login and interactive sessions:
sh -lic ...