[bash] sudo echo "something" >> /etc/privilegedFile doesn't work

This is a pretty simple question, at least it seems like it should be, about sudo permissions in Linux.

There are a lot of times when I just want to append something to /etc/hosts or a similar file but end up not being able to because both > and >> are not allowed, even with root.

Is there someway to make this work without having to su or sudo su into root?

This question is related to bash shell scripting permissions sudo

The answer is


Using Yoo's answer, put this in your ~/.bashrc:

sudoe() {
    [[ "$#" -ne 2 ]] && echo "Usage: sudoe <text> <file>" && return 1
    echo "$1" | sudo tee --append "$2" > /dev/null
}

Now you can run sudoe 'deb blah # blah' /etc/apt/sources.list


Edit:

A more complete version which allows you to pipe input in or redirect from a file and includes a -a switch to turn off appending (which is on by default):

sudoe() {
  if ([[ "$1" == "-a" ]] || [[ "$1" == "--no-append" ]]); then
    shift &>/dev/null || local failed=1
  else
    local append="--append"
  fi

  while [[ $failed -ne 1 ]]; do
    if [[ -t 0 ]]; then
      text="$1"; shift &>/dev/null || break
    else
      text="$(cat <&0)"
    fi

    [[ -z "$1" ]] && break
    echo "$text" | sudo tee $append "$1" >/dev/null; return $?
  done

  echo "Usage: $0 [-a|--no-append] [text] <file>"; return 1
}

Some user not know solution when using multiples lines.

sudo tee -a  /path/file/to/create_with_text > /dev/null <<EOT 
line 1
line 2
line 3
EOT

In bash you can use tee in combination with > /dev/null to keep stdout clean.

 echo "# comment" |  sudo tee -a /etc/hosts > /dev/null

Doing

sudo sh -c "echo >> somefile"

should work. The problem is that > and >> are handled by your shell, not by the "sudoed" command, so the permissions are your ones, not the ones of the user you are "sudoing" into.


The problem is that the shell does output redirection, not sudo or echo, so this is being done as your regular user.

Try the following code snippet:

sudo sh -c "echo 'something' >> /etc/privilegedfile"

Some user not know solution when using multiples lines.

sudo tee -a  /path/file/to/create_with_text > /dev/null <<EOT 
line 1
line 2
line 3
EOT

By using sed -i with $ a , you can append text, containing both variables and special characters, after the last line.

For example, adding $NEW_HOST with $NEW_IP to /etc/hosts:

sudo sed -i "\$ a $NEW_IP\t\t$NEW_HOST.domain.local\t$NEW_HOST" /etc/hosts

sed options explained:

  • -i for in-place
  • $ for last line
  • a for append

This worked for me: original command

echo "export CATALINA_HOME="/opt/tomcat9"" >> /etc/environment

Working command

echo "export CATALINA_HOME="/opt/tomcat9"" |sudo tee /etc/environment

sudo sh -c "echo 127.0.0.1 localhost >> /etc/hosts"

You can also use sponge from the moreutils package and not need to redirect the output (i.e., no tee noise to hide):

echo 'Add this line' | sudo sponge -a privfile

echo 'Hello World' | (sudo tee -a /etc/apt/sources.list)


Using Yoo's answer, put this in your ~/.bashrc:

sudoe() {
    [[ "$#" -ne 2 ]] && echo "Usage: sudoe <text> <file>" && return 1
    echo "$1" | sudo tee --append "$2" > /dev/null
}

Now you can run sudoe 'deb blah # blah' /etc/apt/sources.list


Edit:

A more complete version which allows you to pipe input in or redirect from a file and includes a -a switch to turn off appending (which is on by default):

sudoe() {
  if ([[ "$1" == "-a" ]] || [[ "$1" == "--no-append" ]]); then
    shift &>/dev/null || local failed=1
  else
    local append="--append"
  fi

  while [[ $failed -ne 1 ]]; do
    if [[ -t 0 ]]; then
      text="$1"; shift &>/dev/null || break
    else
      text="$(cat <&0)"
    fi

    [[ -z "$1" ]] && break
    echo "$text" | sudo tee $append "$1" >/dev/null; return $?
  done

  echo "Usage: $0 [-a|--no-append] [text] <file>"; return 1
}

Can you change the ownership of the file then change it back after using cat >> to append?

sudo chown youruser /etc/hosts  
sudo cat /downloaded/hostsadditions >> /etc/hosts  
sudo chown root /etc/hosts  

Something like this work for you?


In bash you can use tee in combination with > /dev/null to keep stdout clean.

 echo "# comment" |  sudo tee -a /etc/hosts > /dev/null

The issue is that it's your shell that handles redirection; it's trying to open the file with your permissions not those of the process you're running under sudo.

Use something like this, perhaps:

sudo sh -c "echo 'something' >> /etc/privilegedFile"

How about:
echo text | sudo dd status=none of=privilegedfile
I want to change /proc/sys/net/ipv4/tcp_rmem.
I did:
sudo dd status=none of=/proc/sys/net/ipv4/tcp_rmem <<<"4096 131072 1024000"
eliminates the echo with a single line document


The problem is that the shell does output redirection, not sudo or echo, so this is being done as your regular user.

Try the following code snippet:

sudo sh -c "echo 'something' >> /etc/privilegedfile"

You can also use sponge from the moreutils package and not need to redirect the output (i.e., no tee noise to hide):

echo 'Add this line' | sudo sponge -a privfile

The issue is that it's your shell that handles redirection; it's trying to open the file with your permissions not those of the process you're running under sudo.

Use something like this, perhaps:

sudo sh -c "echo 'something' >> /etc/privilegedFile"

sudo sh -c "echo 127.0.0.1 localhost >> /etc/hosts"

I would note, for the curious, that you can also quote a heredoc (for large blocks):

sudo bash -c "cat <<EOIPFW >> /etc/ipfw.conf
<?xml version=\"1.0\" encoding=\"UTF-8\"?>

<plist version=\"1.0\">
  <dict>
    <key>Label</key>
    <string>com.company.ipfw</string>
    <key>Program</key>
    <string>/sbin/ipfw</string>
    <key>ProgramArguments</key>
    <array>
      <string>/sbin/ipfw</string>
      <string>-q</string>
      <string>/etc/ipfw.conf</string>
    </array>
    <key>RunAtLoad</key>
    <true></true>
  </dict>
</plist>
EOIPFW"

sudo sh -c "echo 127.0.0.1 localhost >> /etc/hosts"

The problem is that the shell does output redirection, not sudo or echo, so this is being done as your regular user.

Try the following code snippet:

sudo sh -c "echo 'something' >> /etc/privilegedfile"

Doing

sudo sh -c "echo >> somefile"

should work. The problem is that > and >> are handled by your shell, not by the "sudoed" command, so the permissions are your ones, not the ones of the user you are "sudoing" into.


The issue is that it's your shell that handles redirection; it's trying to open the file with your permissions not those of the process you're running under sudo.

Use something like this, perhaps:

sudo sh -c "echo 'something' >> /etc/privilegedFile"

echo 'Hello World' | (sudo tee -a /etc/apt/sources.list)


Can you change the ownership of the file then change it back after using cat >> to append?

sudo chown youruser /etc/hosts  
sudo cat /downloaded/hostsadditions >> /etc/hosts  
sudo chown root /etc/hosts  

Something like this work for you?


The problem is that the shell does output redirection, not sudo or echo, so this is being done as your regular user.

Try the following code snippet:

sudo sh -c "echo 'something' >> /etc/privilegedfile"

Doing

sudo sh -c "echo >> somefile"

should work. The problem is that > and >> are handled by your shell, not by the "sudoed" command, so the permissions are your ones, not the ones of the user you are "sudoing" into.


The issue is that it's your shell that handles redirection; it's trying to open the file with your permissions not those of the process you're running under sudo.

Use something like this, perhaps:

sudo sh -c "echo 'something' >> /etc/privilegedFile"

How about:
echo text | sudo dd status=none of=privilegedfile
I want to change /proc/sys/net/ipv4/tcp_rmem.
I did:
sudo dd status=none of=/proc/sys/net/ipv4/tcp_rmem <<<"4096 131072 1024000"
eliminates the echo with a single line document


This worked for me: original command

echo "export CATALINA_HOME="/opt/tomcat9"" >> /etc/environment

Working command

echo "export CATALINA_HOME="/opt/tomcat9"" |sudo tee /etc/environment

By using sed -i with $ a , you can append text, containing both variables and special characters, after the last line.

For example, adding $NEW_HOST with $NEW_IP to /etc/hosts:

sudo sed -i "\$ a $NEW_IP\t\t$NEW_HOST.domain.local\t$NEW_HOST" /etc/hosts

sed options explained:

  • -i for in-place
  • $ for last line
  • a for append

sudo sh -c "echo 127.0.0.1 localhost >> /etc/hosts"

Doing

sudo sh -c "echo >> somefile"

should work. The problem is that > and >> are handled by your shell, not by the "sudoed" command, so the permissions are your ones, not the ones of the user you are "sudoing" into.


Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"

Examples related to scripting

What does `set -x` do? Creating an array from a text file in Bash Windows batch - concatenate multiple text files into one Raise error in a Bash script How do I assign a null value to a variable in PowerShell? Difference between ${} and $() in Bash Using a batch to copy from network drive to C: or D: drive Check if a string matches a regex in Bash script How to run a script at a certain time on Linux? How to make an "alias" for a long path?

Examples related to permissions

On npm install: Unhandled rejection Error: EACCES: permission denied Warnings Your Apk Is Using Permissions That Require A Privacy Policy: (android.permission.READ_PHONE_STATE) ActivityCompat.requestPermissions not showing dialog box PostgreSQL: role is not permitted to log in Android 6.0 multiple permissions Storage permission error in Marshmallow Android M Permissions: onRequestPermissionsResult() not being called pip install failing with: OSError: [Errno 13] Permission denied on directory SSH Key: “Permissions 0644 for 'id_rsa.pub' are too open.” on mac changing the owner of folder in linux

Examples related to sudo

Composer: file_put_contents(./composer.json): failed to open stream: Permission denied How to run SUDO command in WinSCP to transfer files from Windows to linux How to install Intellij IDEA on Ubuntu? pip install: Please check the permissions and owner of that directory How to use sudo inside a docker container? How to fix 'sudo: no tty present and no askpass program specified' error? npm install errors with Error: ENOENT, chmod npm throws error without sudo Is it acceptable and safe to run pip install under sudo? Command not found when using sudo