Tell me more ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I use this line for images in my mailcap:

image/*; eog %s &;

but mutt immediately deletes the temp file and eog can’t load it.
When I remove the & mutt waits for eog to be closed until it escapes from the command line.

share|improve this question

1 Answer

You could use a wrapper command that:

  1. renames the file
  2. runs the viewer in background
  3. cleans up when the viewer has returned instead of letting mutt do it.

Something like:

#! /bin/sh -

TMPDIR=$(
  mutt -D 2> /dev/null |
    awk -F\" '
      $1 == "tmpdir=" {
        gsub("~", ENVIRON["HOME"], $2)
        print $2
        exit
      }'
)
[ -n "$TMPDIR" ] || exit
export TMPDIR

nargs=$#
nfiles=0
for i do
  case $i in
    ("$TMPDIR"/?*)
      new_file=$(mktemp -ut "XXXXX${i##*/}") &&
        mv -- "$i" "$new_file" &&
        nfiles=$(($nfiles + 1)) &&
        set -- "$new_file" "$@" "$new_file" &&
        continue
  esac
  set -- "$@" "$i"
done

run_command() (
  shift "$(($nargs + $nfiles))"
  exec "$@"
)

(
  run_command "$@"
  while [ "$nfiles" -gt 0 ]; do
    set -- "$@" "$1"
    shift
    nfiles=$(($nfiles - 1))
  done
  shift "$((2*$nargs))"
  rm -f -- "$@"
) &

And put something like:

image/*; muttv eog %s;

Where muttv is that script above.

The above makes no assumption on where the filename(s) appear(s) in the list of arguments or what character they contains... Which is why we first ask mutt what its tmpdir is (so we use that to determine what are the files to view).

In most cases, it would be overkill though, and as Gilles points out may not work if tmpdir is specified as relative to your mailbox folder.

A simpler one would be:

#! /bin/sh -
nargs=$#
eval "file=\${$nargs}"
newfile=$(dirname -- "$file")/new-$(basename -- "$file")
while [ "$nargs" -gt 1 ]; do
  set -- "$@" "$1"
  shift
  nargs=$(($nargs - 1))
done
shift
mv -- "$file" "$newfile" || exit
(
  "$@" "$newfile"
  rm -f -- "$newfile"
) &

Replace mv with cp if you don't want to touch the original file provided by mutt.

share|improve this answer
Gosh, did you just write that from scratch? It took me 15 minutes to understand what you are doing and even now I’m not sure about how some parts work exactly. – Profpatsch Feb 20 at 0:19
Fails with my .muttrc because tmpdir="=tmp". Why not grab the directory from the file name? – Gilles Feb 20 at 19:53
@Gilles, good point about the "+", "="... The whole point was to get tmpdir from mutt so we know which of the arguments is the file name. The whole thing is a bit overkill though anyway as in 99% of the cases the filename is going to occur only once and be the last argument, and we can just rename it to new-$original – Stephane Chazelas Feb 20 at 19:58
Another point is that this entry script isn't always called on behalf of mutt, it could be called in circumstances where the file isn't a temporary file and must not be deleted. (I often call see on the command line, I don't expect it to remove the file, even if it's in /tmp!) Solution: make a hard link. – Gilles Feb 20 at 20:03
@Gilles, I thought of the hardlink, but for mutt, it doesn't work, because after running the command, mutt truncates the file before unlinking it. (open with O_TRUNC and close, I did verify it). – Stephane Chazelas Feb 20 at 20:30
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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