How to non-invasively test for write access to a file?

Just use the -w flag of the test utillity:

[ -w /path/to/file ] && echo "writeable" || echo "write permission denied"

Note that if you're going to write to the file later, it's still possible that you won't be able to write to it. The file may have moved, the permissions may have changed, etc. It can also happen that -w detects write permissions but some other factor intervenes to make the file not writable.


Another approach:

if >> /path/to/file
then
    echo "writeable"
else
    echo "write permission denied"
fi

This will attempt to open the file for appending, and, if that succeeds, run no command (i.e., run a null command) with output to the file. 

Beware that this creates an empty file if it didn't exist.

The -w operator of the test command might just do a stat and then try to figure out whether it looks like you should have access.  My alternative (above) is more reliable than the test approach in some special conditions, because it forces the access check to be done by the kernel rather than the shell.  For example,

  • if the file is on a non-Unix file system – especially if it is remotely mounted from a non-Unix file server – because stat might return a mode value that is misleading.
  • if the file is on a file system that is mounted read-only.
  • if the file has an ACL, and the mode makes it look like you should have access, but the ACL denies it, or vice versa.
  • if some security framework (AppArmor, SELinux, …) denies access to the file.

G-man is right: [ -w ] won't always tell the truth. Here to cope with non-existing file and Permission denied message from shell:

( [ -e /path/to/file ] && >> /path/to/file ) 2> /dev/null && 
  echo writable || 
  echo not writable

Update: Looks frightening, isn't? Well, it is. Hmm... how to phrase it... DON'T USE THIS, unless you perfectly know you are in the conditions it requests to work as expected. See Stephane's comment.

What to conclude, then? Even if [ -w ] does not tell the truth, it is the one command that is intended to do the job. If it does not, well, we'll blame it, write bug reports, and it will work in the future. Better check the conditions under which it works and use [ -w ]; write special code for special cases. Workarounds have their own conditions.

[ -w /path/to/file ]

is the best a priori.