I am trying to automate the addition of a repository source in my arch's pacman.conf file but using the echo
command in my shell script. However, it fails like this:-
sudo echo "[archlinuxfr]" >> /etc/pacman.conf sudo echo "Server = http://repo.archlinux.fr/\$arch" >> /etc/pacman.conf sudo echo " " >> /etc/pacman.conf -bash: /etc/pacman.conf: Permission denied
If I make changes to /etc/pacman.conf manually using vim, by doing
sudo vim /etc/pacman.conf
and quiting vim with :wq
, everything works fine and my pacman.conf has been manually updated without "Permission denied" complaints.
Why is this so? And how do I get sudo echo
to work? (btw, I tried using sudo cat
too but that failed with Permission denied as well)
For solving this error, you need to add the correct permissions to the file to execute. However, you need to be a “root” user or have sudo access for changing the permission. For changing the permission, Linux offers a chmod command. The chmod stands for change mod.
You may open a terminal (press CTRL + ATL + T ) & type man cat to know more about the command and its usage. Further, the difference between cat & using sudo cat ; cat - Frequently & the standard command in use to print an output. sudo cat - Which prints an output with root privilege.
The shell script permission denied error occurs when the shell script you're trying to run doesn't have the permissions to execute. Linux tells you about the problem by showing bash: ./program_name: permission denied on your Linux terminal. Linux and other such OSs are very much concerned about its' security.
As @geekosaur explained, the shell does the redirection before running the command. When you type this:
sudo foo >/some/file
Your current shell process makes a copy of itself that first tries to open /some/file
for writing, then if that succeeds it makes that file descriptor its standard output, and only if that succeeds does it execute sudo
. This is failing at the first step.
If you're allowed (sudoer configs often preclude running shells), you can do something like this:
sudo bash -c 'foo >/some/file'
But I find a good solution in general is to use | sudo tee
instead of >
and | sudo tee -a
instead of >>
. That's especially useful if the redirection is the only reason I need sudo
in the first place; after all, needlessly running processes as root is precisely what sudo
was created to avoid. And running echo
as root is just silly.
echo '[archlinuxfr]' | sudo tee -a /etc/pacman.conf >/dev/null echo 'Server = http://repo.archlinux.fr/$arch' | sudo tee -a /etc/pacman.conf >/dev/null echo ' ' | sudo tee -a /etc/pacman.conf >/dev/null
I added > /dev/null
on the end because tee
sends its output to both the named file and its own standard output, and I don't need to see it on my terminal. (The tee
command acts like a "T" connector in a physical pipeline, which is where it gets its name.) And I switched to single quotes ('
...'
) instead of doubles ("
..."
) so that everything is literal and I didn't have to put a backslash in front of the $
in $arch
. (Without the quotes or backslash, $arch
would get replaced by the value of the shell parameter arch
, which probably doesn't exist, in which case the $arch
is replaced by nothing and just vanishes.)
So that takes care of writing to files as root using sudo
. Now for a lengthy digression on ways to output newline-containing text in a shell script. :)
To BLUF it, as they say, my preferred solution would be to just feed a here-document into the above sudo tee
command; then there is no need for cat
or echo
or printf
or any other commands at all. The single quotation marks have moved to the sentinel introduction <<'EOF'
, but they have the same effect there: the body is treated as literal text, so $arch
is left alone:
sudo tee -a /etc/pacman.conf >/dev/null <<'EOF' [archlinuxfr] Server = http://repo.archlinux.fr/$arch EOF
But while that's how I'd do it, there are alternatives. Here are a few:
You can stick with one echo
per line, but group all of them together in a subshell, so you only have to append to the file once:
(echo '[archlinuxfr]' echo 'Server = http://repo.archlinux.fr/$arch' echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null
If you add -e
to the echo
(and you're using a shell that supports that non-POSIX extension), you can embed newlines directly into the string using \n
:
# NON-POSIX - NOT RECOMMENDED echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null
But as it says above, that's not POSIX-specified behavior; your shell might just echo a literal -e
followed by a string with a bunch of literal \n
s instead. The POSIX way of doing that is to use printf
instead of echo
; it automatically treats its argument like echo -e
does, but doesn't automatically append a newline at the end, so you have to stick an extra \n
there, too:
printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' | sudo tee -a /etc/pacman.conf >/dev/null
With either of those solutions, what the command gets as an argument string contains the two-character sequence \n
, and it's up to the command program itself (the code inside printf
or echo
) to translate that into a newline. In many modern shells, you have the option of using ANSI quotes $'
...'
, which will translate sequences like \n
into literal newlines before the command program ever sees the string. That means such strings work with any command whatsoever, including plain old -e
-less echo
:
echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null
But, while more portable than echo -e
, ANSI quotes are still a non-POSIX extension.
And again, while those are all options, I prefer the straight tee <<EOF
solution above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With