This is probably a duplicate, but all my searches are turning up questions about permission denied errors.

I am running a command in a bash shell. I want to redirect output to append to a file that probably does not exist on the first run. I want to set specific file permissions mode if output redirection has to create this file. Is there a way to do this with one command?

For example, I might try

foo >> /tmp/foo.log 0644

where 0644 are the permissions I want foo.log to end up with. Most commands I've experimented with in bash end up interpreting 0644 as an additional argument to foo.

I get the feeling that this is going to take a second command to chmod the permissions before or after writing to it.

I am using GNU bash 4.2.25 and Ubuntu 12.04, if that makes a difference - general answers are preferred.


There's no way to do it while piping as far as I know, a simple script might be the best solution.

if [ -e /tmp/foo.log ]; then
    foo >> /tmp/foo.log
    foo >> /tmp/foo.log
    chmod 0644 /tmp/foo.log
  • Thanks Slowki, that was my hunch as well. I'm going to leave it open for a few days, in the hopes of attracting a guru to enlighten us. – Patrick M Jan 21 '14 at 17:30
  • 4
    The problem with this approach is that it creates a short time window when the permissions on the file are wrong. I would not use it if the goal is to protect sensitive data. – proski Oct 14 '15 at 17:04
  • 1
    This answer works, as far as it goes, but @proski is right:  the umask answers are better, and one of them should be accepted. – Scott Jun 12 '19 at 18:11

I know it's an old question, but I wanted to add my two cents.

I had the same idea and came up with a solution similar to BowlesCR. The problem with his solution was that my command (foo) wouldn't work if I changed the umask before running it, so this is my take on the problem:

foo | ( umask 0033; cat >> /tmp/foo.log; )

Here, umask only affects the redirection to foo.log in the subshell. Everything else remains unaffected.

A bit convoluted, but it works.

  • Very nice and effective :) Just can't be used with stderr redirection on top of stdout redir. – Orsiris de Jong Apr 8 '17 at 19:28

Without true scripting, you can chain a bit:

touch /tmp/foo.log; chmod 0644 /tmp/foo.log; foo >> /tmp/foo.log

Effectively similar to Slowki's answer, but condensed into a one-liner.

The only other thing I can think of is tinkering with the umask. Best to do this in a subshell so it doesn't pollute the current environment:

(umask 0033 && foo >> /tmp/foo.log)

Two issues with that, though.

  1. Umask can't raise the permissions above the level specified in the creat() syscall (0666 appears to be what Bash uses).
  2. This won't change the permissions on an existing file (because umask applies only to file creation).
  • I'm still new enough to *nix that the umask is still a bit of magic to me. Thanks for the tip, I'll be sure to read up on it. – Patrick M Jan 21 '14 at 19:13
  • Hmm … Still allows an unprivileged process from opening the file and later read its content. – Feuermurmel Apr 16 '17 at 11:28
  • (1) Congratulations on finding an interesting, useful use of cat.  (Although this doesn’t follow the standard pattern of useless uses of cat.)  (2) I presume that you meant to say that bash defaults to mode 0666 when creating files, and so I edited your answer to say so.  (See this, this  … (Cont’d) – Scott Jun 12 '19 at 20:00
  • (Cont’d) …  and this.)  And the question specifically mentions mode 0644.  So a umask value of 22, 23 or 32 would work as well, in this context (you don’t need to use leading zero(s); when modes and umask values are specified numerically, they are always interpreted as octal).  22 is more commonly, conventionally used. – Scott Jun 12 '19 at 20:00
  • @Feuermurmel: So what? The question explicitly calls for mode 644.  We have to assume that the OP knows that 644 means world-readable and intended to make his information public. – Scott Jun 12 '19 at 20:00

When the redirection sets the wrong permissions, e.g.:

$ rm capture.*
$ perl -e 'print STDERR "$$ STDERR\n"; print STDOUT "$$ STDOUT\n"' \
                            >> capture.STDOUT 2>> capture.STDERR
$ perl -e 'print STDERR "$$ STDERR\n"; print STDOUT "$$ STDOUT\n"' \
                            >> capture.STDOUT 2>> capture.STDERR
$ ls -l capture.*
-rw-rw-rw- 1 jcookinf jcookinf 22 Jun 12 10:38 capture.STDERR
-rw-rw-rw- 1 jcookinf jcookinf 22 Jun 12 10:38 capture.STDOUT
$ cat capture.*

I believe you can use something like xynomorf gave, and address the stderr concern from Orsiris de Jong with a slight modification to use the bash process substitution.

$ rm capture.*
$ perl -e 'print STDERR "$$ STDERR text\n"; print STDOUT "$$ STDOUT text\n"' \
            > >(umask 0033; cat >> capture.STDOUT) 2> >(umask 0033; cat >> capture.STDERR)
$ perl -e 'print STDERR "$$ STDERR text\n"; print STDOUT "$$ STDOUT text\n"' \
            > >(umask 0033; cat >> capture.STDOUT) 2> >(umask 0033; cat >> capture.STDERR)
$ ls -l capture.*
-rw-r--r-- 1 jcookinf jcookinf 32 Jun 12 10:43 capture.STDERR
-rw-r--r-- 1 jcookinf jcookinf 32 Jun 12 10:43 capture.STDOUT
$ cat capture.*
233 STDERR text
238 STDERR text
233 STDOUT text
238 STDOUT text

Naturally, use umask 0077 to get mode 600 and prohibit any other users from seeing the contents.


If you want to redirect to a script, unlike umask, with process substitution and install you can also set the execute bit:

install -m 755 <(echo commands go here) newscript

<() places the output into a temporary file, see Process-Substitution

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.