How to make oneliners work with sudo
Ever do a single line shell script such as:
vagrant@manager:~$ ls
target_file.txt
vagrant@manager:~$ cat target_file.txt
vagrant@manager:~$ echo "first line" > target_file.txt
vagrant@manager:~$ cat target_file.txt
first line
vagrant@manager:~$ echo "stuff for end of file" >> target_file.txt
vagrant@manager:~$ cat target_file.txt
first line
stuff for end of file
and that is basically, writing “stuff for end of file” to the end of the file named: target_file.txt.
This is really handy because I don’t need to start up an editor to go in an manually write it out. For one line items, it’s perfect.
The Real Problem
Well, this technique works well when working with normal access files,
special access with sudo
is not required.
With system files such as /etc/hosts
, which controls local mapping
of addresses to names (also known as local DNS
entries),
this is what happens:
vagrant@manager:~$ echo "192.168.0.100 test.server.internal" >> /etc/hosts
-bash: /etc/hosts: Permission denied
Let’s try with sudo
, which I have access:
vagrant@manager:~$ sudo tail /etc/hosts
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
127.0.1.1 ubuntu-xenial ubuntu-xenial
vagrant@manager:~$ sudo echo "192.168.0.100 test.server.internal" >> /etc/hosts
-bash: /etc/hosts: Permission denied
So, what gives?! I have access, do I really have to sudo vim
here??? Ugh, why did I even bother learning these shell tricks?!
A Solution
There’s another utility in the system called sh
, which is an alias
to the command interpreter. On my system, sh
points to dash
agrant@manager:~$ ls -la /bin/sh
lrwxrwxrwx 1 root root 4 Feb 17 2016 /bin/sh -> dash
There’s another body of knowledge I have to check out. ($ man dash
has a slew of information!)
Anyways, to use sh
to help solve my oneliner problem, use sh -c
,
which allows execution of arbitrary programs together. Join this with
sudo
and we get:
vagrant@manager:~$ sudo echo "192.168.0.100 test.server.internal" >> /etc/hosts
-bash: /etc/hosts: Permission denied
vagrant@manager:~$ sudo sh -c 'echo "192.168.0.100 test.server.internal" >> /etc/hosts'
vagrant@manager:~$ sudo tail /etc/hosts
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
127.0.1.1 ubuntu-xenial ubuntu-xenial
192.168.0.100 test.server.internal
And voilà, my oneline can work with sudo
!
One thing to note: for sh -c
to accept the oneliner, wrap the
oneliner program with matching quotes, single or double. The starting
quote style must also be the ending style. So if '
is first, the
oneliner must use "
, and vice versa.
The above example with quotes swapped:
vagrant@manager:~$ sudo sh -c "echo '192.168.0.101 another.server.internal' >> /etc/hosts"
Conclusion
How to solve oneliner problems when using sudo
? Add another command:
sh -c
to solve it!
Whenever I want to do quick oneliners on system files that require
sudo
access, I’ll wrap the command up with sudo -c
, after I tried
the same command on non-system files, of course!