89

I am using the following 2 commands to create a 0B file and set its extn to 644

touch filename.ext chmod 777 filename.txt 

My question is that whether there is any single command in unix (korn shell) that will do the two things together that is to say create a 0B fil with desired permission?

2
  • 6
    Whatever it is that you are hoping to achieve chmod 777 is wrong and dangerous! You should adjust your code to suitable permissions (in most scenarios that's something like 755); and if you have had world writable system files on a public-facing host, reimage the system with sane permissions, and start looking into whether you have been breaking laws through criminal negligence. Commented Feb 22, 2019 at 19:26
  • “set its extn to 644”←I don’t know what ‘extn’ stands for, but seems like mode 644 was the desired outcome. Too late to edit now, since all the answers already assume 777. 🤷 Commented Jun 1, 2022 at 6:53

9 Answers 9

97
install -m 777 /dev/null filename.txt 
Sign up to request clarification or add additional context in comments.

5 Comments

and for a directory => install -m 700 -d /tmp/mydir
For a new script file, install /dev/null script.sh works well because the default permissions for install are 755.
install is used for this purpose. But sadly most of the other approaches will not overwrite existing files, but install does.
It's worth to note, that—as for directory—one can use ol' good mkdir: mkdir -m 700 /tmp/mydir.
The -m stands for --mode=MODE. The -o, --owner=OWNER and -g, --group=GROUP options are also useful.
23

If you want to create the file not just empty but with content and mode at the same time you can use process substitution with install in bash:

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

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

1 Comment

very helpful in installing input files with find & replace mechansim such as sed.
19

First of all, you should NEVER be setting anything to 777 permissions. This is a huge security problem and there just isn't any need for it. For the purposes of this question I will assume you want to create a file with more secure permissions than the defaults, say 600.

There is not a one stop way to safely create AND change the permissions of a file using most bash tools. Even the tricky redirection trick in Paul's answer actually momentarily creates a file with default permissions before resetting them. All new files get created with whatever the system umask value is set too unless the creating program sends very specific requests to the operating system at the time of node creation. A mask of 133 is common, meaning your files get created with 644 permissions out of the box.

Besides using the chmod command to set the file permissions after you create a file, you can also tell the system what defaults you want using the umask command.

$ umask 077 $ touch test_file $ ls -l test_file -rw------- 1 user group 0 Jan 24 22:43 test_file 

You will note the file has been created with 600 permissions.

This will stay in effect for all commands run in a shell until you either close that shell or manually set another value. If you would like to use this construct to run a single command (or even a small set of them) it can be useful to isolate the commands in a subshell

$ (umask 077 ; touch test_file) 

Note that anything else you put inside the parens will use that umask but as soon as you close it, you are back in your previous environment.

5 Comments

NEVER be setting anything to 777 what it means? upload folders on all my websites under nginx feel themself perfect
@Vasilii Then your web server is as full of holes as a cheese cloth. It is not secure, if you are setting anything –much less a publicly served folder– to 777 you are leaving all the doors wide open.
sounds very spooky)) **left to halt the servers
@VasiliiSuricov The correct solution involves several thing: the directory being owned by the same user as the web server, having limited permissions, being marked as containing temporary files, making sure nothing uploaded can ever get mode 7 (execute, +x) permissions, and making sure to tell the web server nothing in there should be run (e.g. php files are only downloadable as raw content, not run as code.
This is good but umask cannot set the execute bits.
17

For bash, simply use chmod with file redirection and history expansion:

chmod 777 filename.txt>>!#:2 

For ksh and zsh you have to drop the history expansion (as shown above, there may be other ways) and use:

chmod 644 filename>>filename 

For scripts of any shell you don't have (and really don't need) history expansion so use the above there as well.

7 Comments

Using this trick a file note still gets created with default umask permissions before getting changed. It is possible for this to fail (power outage, weird ACLs, file system issues, etc.) and leave a file on the system with the wrong permissions. This is a one line shell command but is executed by the shell in two steps. Setting the umask is the proper way to ensure a file is created with the desired permissions at the time it is created.
This may be the best approach but less readable. May you explain about the !#:2 part?
@midnite !#:2 is a history command: ! marks the start of a history command; # refers to this command; :2 refers to the second argument (of this command which is filename.txt).
I assume the >> redirections here should be >, since appending in this context wouldn't make sense. Also, it doesn't make sense to redirect the output of chmod to the file.
@PaulEvans I know it "works" with >>, but that's only when the file doesn't already exist. If it already exists with content, you're going to get the wrong content in it (OP wants "a 0B file"). > is the correct version. Also, redirecting the output of chmod really makes no sense. It makes it look like there's output to redirect, which there's not. This approach also depends on subtle behavior of the shell (creating the output redirection file first, THEN running chmod) and still suffers from the same problem (creating file and then changing permissions in two non-atomic steps).
|
9

You can create your own command:

create () { touch "$1" chmod "$2" "$1" } create filename.ext 644 

1 Comment

no no I think I was not able to place the query properly...it is not about a specific permission or about a specific file name....and the subroutine stuff is the snippet that I am using...I was just wondering whether there is a single command to do both the things together...ike for directories we have mkdir -m 777 dirname...likewise
7

The only reason your files are not created with 666 permissions right off of the bat is the umask. So if you disable the umask:

umask 0 

then when you touch the file it will end up with permissions 666 automatically. It would not be a good idea to make text files executable usually. Directories would end up with 777 permission with umask disabled.

chicks@freecandy /tmp $ umask 0022 chicks@freecandy /tmp $ touch x chicks@freecandy /tmp $ mkdir xx chicks@freecandy /tmp $ umask 0 chicks@freecandy /tmp $ touch y chicks@freecandy /tmp $ mkdir yy chicks@freecandy /tmp $ ls -ld x xx y yy -rw-r--r-- 1 chicks chicks 484 Jan 24 14:37 x drwxr-xr-x 2 chicks chicks 4096 Jan 24 14:37 xx -rw-rw-rw- 1 chicks chicks 0 Jan 24 14:37 y drwxrwxrwx 2 chicks chicks 4096 Jan 24 14:37 yy 

2 Comments

How do you change umask back to its former value afterward?
Start a new shell before changing the umask, then you can just exit that shell to get the old umask back. unix.stackexchange.com/a/65890/79839
5

touch filename.ext && chmod 777 $_

$_ is the most recent parameter

but as others have said 777 isn't a good idea

Comments

2

Applying this to Docker

Because of Docker and Alpine, I imagine there are a lot of people interested in creating executable one-liners without the help of bash-isms. It's pretty simple with install

$ docker build -t temp - <<EOF FROM alpine RUN echo "date" | install -m 775 /dev/stdin /bin/now CMD /bin/now EOF Sending build context to Docker daemon 2.048kB Step 1/3 : FROM alpine ---> d6e46aa2470d Step 2/3 : RUN echo "date" | install -m 775 /dev/stdin /bin/now ---> Running in 95919b575638 Removing intermediate container 95919b575638 ---> cd1fafd96ef3 Step 3/3 : CMD /bin/now ---> Running in 03b5c3ac7265 Removing intermediate container 03b5c3ac7265 ---> 8f30b527dd29 Successfully built 8f30b527dd29 Successfully tagged temp:latest $ docker run --rm temp Thu Nov 12 07:44:24 UTC 2020 $ docker run --rm temp ls -la /bin/now -rwxrwxr-x 1 root root 5 Nov 12 07:44 /bin/now $ docker rmi temp Untagged: temp:latest Deleted: sha256:8f30b527dd29203b67c86290b34b0a29d3c98a48134609d0b1e2b89087a7d6e7 Deleted: sha256:cd1fafd96ef3084226c5f98f472e3e08bc9a9f0448cc3e68b6f1c192d12d778a Deleted: sha256:e58c75acbf953a64d35089cf50e1c5b762601e1cb9d9d1d668e135f23ce1fe86 

Update

A commenter said:

I don't get what this has to do with the question.

  1. The OP's subject for this Q was "Single command to create a file and set its permission"
  2. The OP included "single command in unix (korn shell) that will do the two things together"

The subject causes this Q to come up for Docker users' Google searches. The OP specified "korn shell" which implies avoiding bash specific features. Because Alpine and many other minimal Linux bases used in containers does not include bash, the top ranked answer is not going to work for them. My answer does work for them and the OP's korn shell. Using Docker to demonstrate a solution means that anyone using Linux, macOS, Windows, or WSL2 in Windows can easily recreate the demo on their machine by reading the transcript from my machine.

7 Comments

I don't get what this has to do with the question.
This answer does add something useful - how to create a file with the given permissions and content piped from stdin. The other parts of this answer simply demonstrate that the technique works, so that is useful as well, though I think it could be made a bit clearer.
Unfortunately this seems to not be portable to different OSes, for example on MacOS 12.3.1 I get the error install: /dev/stdin: Inappropriate file type or format.
@KenWilliams that's really interesting. The host OS should not matter because the line echo "date" | install -m 775 /dev/stdin /bin/now is run inside an Alpine Linux container. I'll have to check if something chained in later versions of Alpine. Luckily I included a full transcript and can use the hash d6e46aa2470d to compare.
I should have clarified - when not running this in Alpine (Docker or otherwise), install isn't guaranteed to be able to deal with device files. It's too bad, because it would have been the perfect solution for my use case (content piped from an echo).
|
0

This has a lot of interesting commentary but I'd like to clear up a few things.

Firstly, umask removes requested permissions. Files do not get created with the default umask permissions. Also, there is no default umask value, per se, its up to your system to create your process with a umask value. When a process requests that a file be created, (e.g., with creat(), openat()) it specifies permissions, the kernel removes the umask bits from the requested permission bits and the result is the resulting permissions.

Secondly, I think the install command answers are quite good. But, it should be noted that the install command first sets its process umask to 0 and then creates the file with an openat() and permission mode 0600 and then changes the mode with fchmodat(). There is a race condition here where the file exists with permissions 0600 before they are set to those requested. You can verify this with the strace command. e.g., strace -o /tmp/s.out install -m 754 /dev/null MYFILE . I was on Ubuntu 24.04 and the install command was version 9.4

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.