74

I have a new Ubuntu 12.04 VPS. I am trying to write a setup script that completes an entire LAMP installation. Where I am having trouble is appending a line to the /etc/hosts file. My current hosts file looks like this:

127.0.0.1       localhost Venus

# 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

I would like it to look like this:

127.0.0.1       localhost Venus
192.241.xx.xx  venus.example.com venus

# 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

I have tried a variety of sed commands using the append (\a) command. For some reason Ubuntu either just echoes the contents of the hosts file in terminal or does nothing at all. How would I properly inject the second line into the file with a bash script?

jww
  • 97,681
  • 90
  • 411
  • 885
Stephen Howells
  • 909
  • 1
  • 7
  • 11
  • https://github.com/alphabetum/hosts looks like a good solution if you are allowed to install packages – revau.lt Dec 08 '17 at 10:01

7 Answers7

67

Make sure to use the -i option of sed.

-i[SUFFIX], --in-place[=SUFFIX]
  edit files in place (makes backup if extension supplied)

sed -i "2i192.241.xx.xx  venus.example.com venus" /etc/hosts

Otherwise,

echo "192.241.xx.xx  venus.example.com venus" >> /etc/hosts

would append the line at the end of the file, which could work as you expect.

damienfrancois
  • 52,978
  • 9
  • 96
  • 110
  • 1
    This assumes that the 127.0.0.1 line is the first line of the input stream (that the insert should be done on the second line). That is probably correct in many cases, but it bears mentioning. – kojiro Oct 12 '13 at 21:45
  • 5
    -bash: /etc/hosts: Permission denied. Any ideas? – Alex2php Mar 20 '14 at 14:00
  • 1
    @Alex2php Make sure you have root access to modify that file. – damienfrancois Mar 20 '14 at 14:01
  • 17
    This one solved for me: sudo -- sh -c "echo test >> /etc/hosts" just sudo doesn't work if i try to append something… – Alex2php Mar 20 '14 at 14:04
  • 3
    Note that on Mac, you need to specify `-i ''` such as `sed -i '' '2i192.241.11.22 venus.example.com venus' /etc/hosts`. The Mac version of sed requires the extension parameter for `-i`, even if it's empty. – Doktor J Aug 20 '14 at 17:59
  • With sed you should use `$ a` option to append to last line, see: https://stackoverflow.com/a/50003244/658497 – Noam Manos Apr 24 '18 at 14:17
  • why i have an error sed: -e expression #1, char 3: unknown command: `.' ? – razor Jan 02 '19 at 11:20
  • sed -i "$(awk '/^$/{print NR; exit}' /etc/hosts)i192.xxx.xxx venus.example.com venus" /etc/hosts – ICIM Jun 13 '23 at 08:00
48

If your in mac or you need sudo permission to this try this:

sudo -- sh -c -e "echo '192.34.0.03   subdomain.domain.com' >> /etc/hosts";

It will still ask you for password.

alternative way from @kainjow

echo '192.34.0.03 subdomain.domain.com' | sudo tee -a /etc/hosts
Jirapong
  • 24,074
  • 10
  • 54
  • 72
Jsonras
  • 1,120
  • 13
  • 10
  • 8
    You can also use `tee`: `echo '192.34.0.03 subdomain.domain.com' | sudo tee -a /etc/hosts` – kainjow Jun 10 '16 at 21:20
  • 1
    This seems to be the case for ubuntu 16 too. – Francisco Luz Dec 22 '16 at 15:53
  • Perfect, just what I was looking for. I'd love to know what exactly `-- sh -c -e` does though? I prefer to know what I'm putting in my terminal rather than just copy pasting :) – powerbuoy Jan 10 '17 at 11:22
  • You don't need `-e` – spex Jun 28 '17 at 15:48
  • 2
    @powerbuoy The double tack `--` is used in shell commands to signify the end of command options, after which only positional parameters are accepted. The `sh` is the shell command interpreter used with the flag `-c` which causes the commands to be read from the string operand instead of from the standard input. The `-e` flag is unnecessary for our use case, but it causes the interpreted command to exit immediately if any untested command fails in non-interactive mode. – spex Jun 28 '17 at 15:54
  • ! beware, this would completely overwrite your `hosts` file. make sure you backup your `hosts` file before proceeding with `tee`. Backup the file like `sudo cp /etc/hosts /etc/hosts.bak`. – Artem Kozlenkov Feb 09 '21 at 12:53
37

Insert/Update Entry

If you want to programmatically insert/update a hosts entry using bash, here's a script I wrote to do that:

#!/bin/bash

# insert/update hosts entry
ip_address="192.168.x.x"
host_name="my.hostname.example.com"
# find existing instances in the host file and save the line numbers
matches_in_hosts="$(grep -n $host_name /etc/hosts | cut -f1 -d:)"
host_entry="${ip_address} ${host_name}"

echo "Please enter your password if requested."

if [ ! -z "$matches_in_hosts" ]
then
    echo "Updating existing hosts entry."
    # iterate over the line numbers on which matches were found
    while read -r line_number; do
        # replace the text of each line with the desired host entry
        sudo sed -i '' "${line_number}s/.*/${host_entry} /" /etc/hosts
    done <<< "$matches_in_hosts"
else
    echo "Adding new hosts entry."
    echo "$host_entry" | sudo tee -a /etc/hosts > /dev/null
fi

The script is intended for use with OS X but would work on linux as well with minor tweaking.

brismuth
  • 36,149
  • 3
  • 34
  • 37
  • too complex script to add just a line – José Ibañez Feb 13 '19 at 22:48
  • 4
    This is a better solution to just adding a line to etc/hosts imo – CodeUK Apr 19 '20 at 15:30
  • this is perfect, although update part is not working as expected, it still continued adding the line even if the ipaddress and hostname combination existed. also did a little tweak so that instead of hardcoding the script will take ipaddress and host name as an argument. – Kalpesh Popat Jun 20 '20 at 09:51
  • Great, thanks! Just changed the grep regex slightly to `grep -n "^[^#]*${host_name}" /etc/hosts` to also ignore potential matches in commented lines – tomorrow Nov 09 '21 at 15:40
5
echo "127.0.0.1 localhost `hostname`">./temp_hosts
echo "192.241.xx.xx  venus.example.com">>./temp_hosts
cat /etc/hosts |tail -n +2 >>./temp_hosts
cat ./temp_hosts > /etc/hosts
rm ./temp_file
Vladimir Dimitrov
  • 1,008
  • 7
  • 21
  • Thank you for your response, Vladimir. I will test your method as well and post if it worked for me to benefit any future visitors to this question. – Stephen Howells Oct 12 '13 at 21:34
  • @Ingo Do you really think it's appropriate to suggest that someone *not* try something (assuming that thing is not dangerous)? Let the man experiment! – kojiro Oct 12 '13 at 21:53
2

I should point out that sed (the stream editor) is not actually intended for editing files, although it can be used to do that. (Standard sed doesn't have a built-in mechanism for writing to other than standard output.) A more appropriate tool would be ed.

The following ed script says "find the line containing the (admittedly sloppy) regular expression /127.0.0.1/ and append at the next line." (The lone period tells ed to stop appending.)

ed /etc/hosts <<-'EOF'
    /127.0.0.1/a
    192.241.xx.xx  venus.example.com
    .
    wq
EOF

That said, you can really just append this line to the end of your /etc/hosts file very trivially:

echo '192.241.xx.xx  venus.example.com' >> /etc/hosts
kojiro
  • 74,557
  • 19
  • 143
  • 201
  • 1
    I've never used `ed` before. It seems very powerful and will come in handy. Thank you for sharing. – Stephen Howells Oct 12 '13 at 21:49
  • For some users, depending on their permissions setup, you may need to `sudo -- sh -c "echo '192.241.xx.xx venus.example.com' >> /etc/hosts"` as simply `sudo echo ...` will result in a `permission denied`. – spex Jun 28 '17 at 16:01
1

you can use sed, like:

sed '/Venus/ a\  
192.241.xx.xx  venus.example.com venus' /etc/hosts
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
-1

try this with root access.

 public void edithost() {
    sudo("echo " + "192.168.43.1     www.openrap.com openrap" + " >> /etc/hosts");
    sudo("echo " + "192.168.43.1  openrap.com openrap" + " >> /etc/hosts");
    sudo("echo " + "192.168.2.144  www.openrap.com openrap" + " >> /etc/hosts");
    sudo("echo " + "192.168.2.144  openrap.com openrap" + " >> /etc/hosts");
}

sudo for super user permission

public static void sudo(String... strings) {
    try {
        Process su = Runtime.getRuntime().exec("su");
        DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());

        for (String s : strings) {
            outputStream.writeBytes(s + "\n");
            outputStream.flush();
        }

        outputStream.writeBytes("exit\n");
        outputStream.flush();
        try {
            su.waitFor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

this will append the lines to hosts in the android

sanjay
  • 695
  • 11
  • 22