15

I have bash script which modified file like this

sed -i "/hello world/d" /etc/postfix/virtual

and I ran this script from web application. sed command create temporary file in that directory but user under which web application works doesn't have permissions to create files in that directory. I do not want to give more permissions for the user to that folder. Is it possible to specify temp file location for sed command?

I am new in linux so sorry if my question is too easy but I didn't find any solution.

Thanks!

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
Radislav
  • 2,892
  • 7
  • 38
  • 61
  • What about redirecting the file? `sed "..." /etc/.../virtual > new_file` Unless you really need to modify in place. – fedorqui Nov 22 '13 at 13:38
  • I got the same problem : I put myself in the root group, and chmoded +x the /etc/hosts file, to be able to script a change (with sed -i) in it. Have you found a solution ? – Pierre-Olivier Vares May 13 '16 at 09:58

7 Answers7

6

The file must be modified via temporary file, this is actually what sed was doing but it lacked permissions.

When dealing with such a situation, we just do this process manually.

## TEMP File
TFILE=`mktemp --tmpdir tfile.XXXXX`
trap "rm -f $TFILE" 0 1 2 3 15

##
sed 's_XXX_YYY_' /etc/example > "$TFILE"
cat "$TFILE" > /etc/example

## trap Deletes TFILE on Exit
J. M. Becker
  • 2,755
  • 30
  • 32
  • 2
    The above works because you can set the configuration file to allow the edit, while still having the containing directory protected. In my case, I set the group and group permissions to allow my personal account to edit the file, but left all other permissions unchanged. The temporary file isn't in the directory, so it isn't affected, and the configuration file will permit the cat to work. – EdwinW Aug 02 '15 at 15:40
5

You could use "sponge" from moreutils.

sed  "/hello world/d" /etc/postfix/virtual | sponge /etc/postfix/virtual
MaEtUgR
  • 353
  • 3
  • 8
Harold Zoid
  • 51
  • 1
  • 1
4

Old question, but I was surprised to find nobody suggesting to use some good-ol' RAM via a variable. Here's what I ended up doing, no need for a temp file at all:

TEMP_SED=$(sed "/hello world/d" /etc/postfix/virtual)
echo "$TEMP_SED" > /etc/postfix/virtual
unset TEMP_SED

Note the quotes around the variable when echoing. This is needed to preserve any newlines in the file.

Raphael Amoedo
  • 4,233
  • 4
  • 28
  • 37
CenterOrbit
  • 6,446
  • 1
  • 28
  • 34
  • 1
    Also, I've finally found someone else in this world that frequently has to deal with pesky "hello world"s cropping up in their postfix virtual file. – CenterOrbit Nov 16 '19 at 20:55
  • Variation without unset: $(TEMP_SED=`sed "/hello world/d" /etc/postfix/virtual && echo "$TEMP_SED" > /etc/postfix/virtual) – Nicolas Albert Jan 24 '23 at 15:23
2

You can always avoid inline editing:

sed "/hello world/d" /etc/postfix/virtual > /tmp/_foo

# mv /tmp/_foo /etc/postfix/virtual

But let me caution a web user editing /etc/postfix/virtual is pretty risky.

anubhava
  • 761,203
  • 64
  • 569
  • 643
1

AFAIK, you can't configure sed for that. So, you have to run your command with the required privileges.

  • create a script named, for example, update-postfix (it can have arguments), and put in /usr/local/bin

    #!/bin/bash
    sed -i "/$1/d" /etc/postfix/virtual
    
  • Create a file in /etc/sudoers.d/ (whatever its name, it can be update-postfix or something more generic), replacing _user_ with the one calling your script :

    _user_ ALL = (root) NOPASSWD: /usr/local/bin/update-postfix
    

    It allows _user_ to run update-postfix (and ony this command) as root

  • In your script, call sudo update-postfix helloworld instead of the sed command. The update-postfix script is called as the root user.

NB : Called as such, your script (update-postfix) has right to do anything, so be careful what you put in, and sanitize the arguments (what I didn't do here for brevity).

Pierre-Olivier Vares
  • 1,687
  • 15
  • 20
0

Simple custom temp file solution, similar to the solution by @techzilla for those not wanting to use the trap --

sed  "/hello world/d" /etc/postfix/virtual > /tmp/temp_postfix_update && cat /tmp/temp_postfix_update > /etc/postfix/virtual && rm -f /tmp/temp_postfix_update

Per what @EdwinW said, piping the input using cat doesn't remove the file so the write permissions on the file persist.

storm_m2138
  • 2,281
  • 2
  • 20
  • 18
0

I couldn't find a solution but if /etc/postfix/virtual is a soft link and you have permission on the underlying, execute sed on the underlying

$ cat  /etc/postfix/virtual
### :-)
hello world
$ ls -lda /etc/postfix/virtual /etc/postfix
dr-xr-xr-x. 2 root root 21 Apr 10 10:39 /etc/postfix
lrwxrwxrwx. 1 root root 27 Apr 10 10:39 /etc/postfix/virtual -> /home/user1/postfix/virtual
$ sed -i "/hello world/d" /etc/postfix/virtual
sed: couldn't open temporary file /etc/postfix/sedmVfrMC: Permission denied
$ sed -i "/hello world/d" /home/user1/postfix/virtual
$ cat  /etc/postfix/virtual
### :-)
$ ls -lda /etc/postfix/virtual /etc/postfix
dr-xr-xr-x. 2 root root 21 Apr 10 10:39 /etc/postfix
lrwxrwxrwx. 1 root root 27 Apr 10 10:39 /etc/postfix/virtual -> /home/user1/postfix/virtual
$