Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

(v) ugly (and simple) bash script...

7 views
Skip to first unread message

Morgan Read

unread,
May 21, 2022, 5:30:05 AM5/21/22
to
Hi List,

I'm in the process of solving the removal of movemail from T'bird and I
feel like I'm on the home straight.

I've swapped T'bird from mbox to Maildir and swapped postfix delivery
from mbox to Maildir and the last bit of the puzzle is moving the
delivered mail from `~/Maildir/new/*` to `~/Maildir/cur/*.eml` (after
linking `~/Maildir` to `[T'bird profile]/Mail/Local Folders/Inbox` .

With a little help from Greg Wooledge:
https://mywiki.wooledge.org/BashFAQ/030
I've come up with:
`cd ~/Maildir/new/; for f in *; do mv -- "$f" ~/Maildir/cur/"${f%}.eml";
cd -; done`
Which perhaps does the job...

```
cd ~/Maildir/new/; for f in *; do echo mv -- "$f"
~/Maildir/cur/"${f%}.eml"; cd -; done
mv -- 1653057612.Vfe06I3000a2M156375.morgansmachine
/home/morgan/Maildir/cur/1653057612.Vfe06I3000a2M156375.morgansmachine.eml
/home/morgan
```

But, that doesn't seem very elegant to me and I strongly suspect that it
can be done a lot better than I have managed on my own - I realise I
need to reference the file `*` in `~/Maildir/new/*` but couldn't work
out how to do that without also referencing the whole long filename -
which gave me
`/home/morgan/Maildir/cur//home/morgan/Maildir/new/1653057612.Vfe06I3000a2M156375.morgansmachine.eml`
...

Getting postfix to run that command on mail delivery is the next question?

Thanks
--
Morgan Read

Greg Wooledge

unread,
May 21, 2022, 10:00:05 AM5/21/22
to
On Sat, May 21, 2022 at 10:08:42AM +0100, Morgan Read wrote:
> I've come up with:
> `cd ~/Maildir/new/; for f in *; do mv -- "$f" ~/Maildir/cur/"${f%}.eml"; cd
> -; done`

You aren't checking whether the first cd succeeds. If it fails for any
reason, you're going to end up moving file(s) out of wherever you happen
to be at the time.

You also don't want that "cd -" to be *inside* the loop. If there's more
than one file in ~/Maildir/new/, you're going to move the first one, then
cd back to where you were, then try to move the second file by its
relative name from the directory you changed *back* to. There probably
won't be a file by that name in the original directory, so it'll probably
give an error... but if it doesn't, then you've screwed up big time.

If this is a script, you don't need the "cd -" at all. Just let the
script exit, and it won't matter what directory it ended in.

Finally, ${f%} is just a fancy way of writing $f. You're literally saying
"take the value of $f but remove the empty string from the end of it".

#!/bin/sh
cd ~/Maildir/new/ || exit 1
for f in *; do
mv -- "$f" ../cur/"$f.eml"
done

> Which perhaps does the job...

I must admit I do not understand what the "job" actually is, or why
you're doing this.

> Getting postfix to run that command on mail delivery is the next question?

Now that looks like something closer to an actual goal statement. I
still don't understand why you want messages to be marked as "not new"
and given a different filename, but presumably there is some rationale
for it.

I don't know postfix, but presumably what you want to do here is find
whatever mechanisms or hooks it has for performing local mail deliveries.
Arrange for your script to be executed after a successful delivery to
~/Maildir/.

In qmail, local delivery is controlled by the user's ~/.qmail file
(or ~/.qmail-* for the user's personal address space). Inside the ~/.qmail
file, a local delivery to a Maildir is indicated by a line beginning
with . or / and ending with / . A program to be executed is indicated by
a line beginning with | .

So, to do this in qmail, you could create a ~/.qmail file containing
something like this:

./Maildir/
|./bin/myscript

"myscript" will be fed the content of the email being delivered on stdin,
but you can simply ignore that.

I'm guessing postfix has something similar to this. You'll have to read
up on it yourself. Pay close attention to how postfix interprets the
exit status of the programs that you run, and make sure you exit with
an appropriate status. For example, in the example script I gave above,
if the cd fails, I told it to exit with status 1. But status 1 is not
explicitly defined by qmail-command(8), so another exit status might
be more appropriate. I also didn't check whether the mv succeeds. You
might want to do that, and abort with a specific exit status if any
mv command fails.

Dan Ritter

unread,
May 21, 2022, 10:40:05 AM5/21/22
to
Greg Wooledge wrote:
> On Sat, May 21, 2022 at 10:08:42AM +0100, Morgan Read wrote:
> > I've come up with:
> > `cd ~/Maildir/new/; for f in *; do mv -- "$f" ~/Maildir/cur/"${f%}.eml"; cd
> > -; done`
>
> You aren't checking whether the first cd succeeds. If it fails for any
> reason, you're going to end up moving file(s) out of wherever you happen
> to be at the time.

This looks like a bizarre kind of Maildir delivery recipe that
would better be handled by a proper delivery tool; I generally
recommend the maildrop package, which supplies an excellent mail
filtering language.


> > Getting postfix to run that command on mail delivery is the next question?
>
> Now that looks like something closer to an actual goal statement. I
> still don't understand why you want messages to be marked as "not new"
> and given a different filename, but presumably there is some rationale
> for it.
>
> I don't know postfix, but presumably what you want to do here is find
> whatever mechanisms or hooks it has for performing local mail deliveries.

Postfix can either hand this off globally, per address, or
per-user. Per-user config is set up in ~/.forward which at its simplest
is one line per delivery, e.g.:

|/usr/bin/maildrop

Documentation is in `man 8 local`
http://www.postfix.org/local.8.html

> I'm guessing postfix has something similar to this. You'll have to read
> up on it yourself. Pay close attention to how postfix interprets the
> exit status of the programs that you run, and make sure you exit with
> an appropriate status.

This is in the man section on EXTERNAL COMMAND DELIVERY.

-dsr-

john doe

unread,
May 21, 2022, 12:40:05 PM5/21/22
to
On 5/21/2022 3:55 PM, Greg Wooledge wrote:
> On Sat, May 21, 2022 at 10:08:42AM +0100, Morgan Read wrote:
>> I've come up with:
>> `cd ~/Maildir/new/; for f in *; do mv -- "$f" ~/Maildir/cur/"${f%}.eml"; cd
>> -; done`
>
> You aren't checking whether the first cd succeeds. If it fails for any
> reason, you're going to end up moving file(s) out of wherever you happen
> to be at the time.
>
> You also don't want that "cd -" to be *inside* the loop. If there's more
> than one file in ~/Maildir/new/, you're going to move the first one, then
> cd back to where you were, then try to move the second file by its
> relative name from the directory you changed *back* to. There probably
> won't be a file by that name in the original directory, so it'll probably
> give an error... but if it doesn't, then you've screwed up big time.
>
> If this is a script, you don't need the "cd -" at all. Just let the
> script exit, and it won't matter what directory it ended in.
>
> Finally, ${f%} is just a fancy way of writing $f. You're literally saying
> "take the value of $f but remove the empty string from the end of it".
>
> #!/bin/sh
> cd ~/Maildir/new/ || exit 1
> for f in *; do
> mv -- "$f" ../cur/"$f.eml"
> done
>

+1 for readability in a script.

I would also bail out if the mv command fails:

for f in *; do
mv "$f" ../cur/"${f}.eml" || exit $?
done

--
John Doe
0 new messages