I have such strings in my /etc/mail/virtusertable

mail1@example.com    error:nouser Account temporary disabled
mail2@example.com    error:nouser Account temporary disabled
mail3@example.com    error:nouser Account temporary disabled

And I want to replace all error:nouser Account temporary disabled with appropriate virtuser_NNN which I can get from /etc/dovecot/dovecot.passwd

I tried different variants but all with the same result. All error:nouser Account temporary disabled replaced with first virtuser_NNN from /etc/dovecot/dovecot.passwd

After running my script it looks like

mail1@example.com    virtuser_1
mail2@example.com    virtuser_1
mail3@example.com    virtuser_1

My script is:

 cat /etc/mail/virtusertable_back | grep example.com |
 grep 'error:nouser Account temporary disabled' | awk '{print $1}' |
 xargs -I{} grep {} /etc/dovecot/dovecot.passwd | awk -F'::' '{print $2}' |
 xargs -I{} sh -c 'grep {} /etc/passwd' | awk -F: '{print $1}'|
 xargs -n1 -P1 -I{} sed -i 's/error\:nouser Account temporary disabled/{}/' /etc/mail/virtusertable_back

Yes, I'm doing this on the copy of /etc/mail/virtusertable.

And /etc/dovecot/dovecot.passwd has records in such format:

mail@example.com:*$1$hash here:user id:group id::/var/www/userlogin/data/email/example.com/mail:::/var/mail/virtuser_NNNN

Need to add, that I want to change strings with err message to appropriate virtusers only for specific mail domain, not the to the whole file.

  • Please edit your question and show us an excerpt of your /etc/dovecot/dovecot.passwd file. I am guessing that it has an email as the first field and a username as the second, is that correct? – terdon Nov 22 '15 at 14:12
  • I've updated my question with info about strings format in my /etc/dovecot/dovecot.passwd – Nokse Nov 22 '15 at 14:29

I would do this in Perl. Save the email and associated username from the /etc/dovecot/dovecot.passwd in a hash and then replace in /etc/mail/virtusertable:

$ perl -i -ape 'BEGIN{
                    while(<$fh>){ @G=split(/:/); $k{$G[0]}=$G[2]; }
            s/error:nouser Account temporary disabled/$k{$F[0]}/ if defined $k{$F[0]};
'  /etc/mail/virtusertable > newfile


The -i makes perl edit its input file in place, same as sed -i. The -a makes it split each input line on whitespace into the array @F. Just like awk. The -p means "print every line after applying the script given by -e".

The script itself reads /etc/dovecot/dovecot.passwd in the BEGIN{} block (so before reading the input file, /etc/mail/virtusertable), splits each line on : into the @G array and then saves each email as a key in the hash %k whose values are the user names.

Once that is finished, it moves on to process /etc/mail/virtusertable and replaces each error:nouser Account temporary disabled with the user name corresponding to the email on the 1st field if that user name is defined.


The following pipeline should work well provided there are no backslashes in virtuser_NNN names:

cut  -d:  -f1 "$pw" |  
grep -Fnf-    "$tbl"|
sed  -e's|:.*/\(.*\)|s/:nouser/:\1/|' | 
sed  -f-      "$tbl"

It will:

  • first cut away all but the first sequence of any not-colon characters for each line of dovecot.passwd

  • grep for -Fixed-string matches to the results in virtusertable

  • s///ubstitute away all but the line-number and the last occurring not-slash sequence of characters from those results into a string like:

    • [LINENO]s/:nouser/:not-slashes/
  • finally use that output as a sed script against virtusertable

  • Nice solution to replace strings in whole file, but what I actually need is to replace err messages only for specific domain. I've updated my question with this detail. – Nokse Nov 22 '15 at 18:55
  • @Nokse - you mean you want to replace nouser? – mikeserv Nov 22 '15 at 19:15
  • I mean, that there are lots of correct lines like: some_user@example.com virtuser_3587 but also there present lines like I mentioned before: mail3@example.com error:nouser Account temporary disabled for different mailboxes on different domains. And I want to replace this error:nouser Account temporary disabled with correct virtuser_"number" only for specific domain. Hope now its clear – Nokse Nov 22 '15 at 19:21
  • @Nokse - not really clear to me. the best way to get your point across is to edit your question with actual examples of input -> output. if there are some lines in a file which you don't want affected, include some lines like those in your example and specify what it is about them that shouldn't be changed. be clear about what it is that needs changing, and from what source and under what conditions the change ought to be had. – mikeserv Nov 22 '15 at 20:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.