28

Attention please:

I am not asking how to make a file from the command line!


I have been using touch for making files for years without paying attention that its main purpose is something else. If one wants to create a file from command line there are so many possibilities:

touch foo.bar
> foo.bar
cat > foo.bar
echo -n > foo.bar
printf '' > foo.bar

And I'm sure there are more.

But the fact is, none of the commands above are actually designed for creating files. For example, man touch suggests this command is for changing file timestamps. Why doesn't an OS as complete as Unix (or Linux) have a command solely designed for creating files?

Pouya
  • 875
  • Most of the time creating an empty file is a workaround, there kernel function to create files. but there's few interest in having a dedicated command just to create files – Kiwy Apr 10 '14 at 11:36
  • 35
    Why would you clutter the system to add a command to do something that can be done a dozen ways with tools that already exist? – Michael Kohne Apr 10 '14 at 11:49
  • 4
    Why is there no command for reading files from/to streams/stdin/out? Everyone uses the command intended for concatenation! – SF. Apr 10 '14 at 12:07
  • 2
    @MichaelKohne, I see your point, with all due respect, I have a problem with it. With this approach there are many commands that are only cluttering the system. Why use more when less does more than what more do!? Or dir and ls. Albeit, I'm aware of compatibility issues. – Pouya Apr 10 '14 at 12:08
  • 9
    more predates the creation of less. less has been created specifically to address shortcomings of more. more still exists for backward compatibility reasons. dir and ls are, for most intents and purposes, the same executable - they differ only in a handful of bytes. A new tool intended specifically for creating files would do less than existing tools, and as such it would be a regression, not an improvement like in the case of less vs more. – lanzz Apr 10 '14 at 13:46
  • @lanzz And now we also have vim - (vim read from stdin) which AFAIK does even more than less ;) – Izkata Apr 10 '14 at 14:11
  • 1
    Plus we need to look at the legacy, Unix was created when each byte was counted. Why create a utility for a task that you can do with an already existing utility? – Thomas BDX Apr 11 '14 at 01:52
  • Isn't the shell builtin for creating a new file the > character? I think the basis of this question is flawed. – krowe Apr 11 '14 at 02:51
  • You left out cp /dev/null foo.bar. – user1024 Apr 11 '14 at 05:48
  • It would be more intuitive to have a command such as 'create_file', rather than 'cat', in order to create files. – john-jones Apr 30 '14 at 16:15
  • @michael Kohne, because the new command would offer a more intuitive way of achieving that end. – john-jones May 01 '14 at 13:21
  • echo 'This is an example file.' > example.txt – Brian May 30 '16 at 19:53
  • 1
    OP is very clear: "I am not asking how to make a file from the command line!" – don_crissti May 30 '16 at 20:02

4 Answers4

40

I would say because it's hardly ever necessary to create an empty file that you won't fill with content immediately on the command line or in shell scripting.

There is absolutely no benefit in creating a file first and then using I/O redirection to write to the file if you can do so in one step.

In those cases where you really want to create an empty file and leave it I'd argue that > "${file}" could not be briefer and more elegant.

TL;DR: It doesn't exist because creating empty files most often has no use, and in cases it has there are already a myriad of options available to achieve this goal.

On a side note, using touch only works if the file does not exist whereas options using redirection will always truncate the file, even if it exists (so technically, those solutions are not identical). > foo is the preferred method since it saves a fork and echo -n should be avoided in general since it's highly unportable.

  • 1
    I found your point about creating the file and then using I/O tools, very solid. Thank you. – Pouya Apr 10 '14 at 12:10
  • "options using redirection will always truncate the file, even if it exists". Isn't there a way to append using redirection? – Faheem Mitha Apr 10 '14 at 12:26
  • 1
    @FaheemMitha Yes (>>). I was referring to the examples given by OP using >. Appending would be quite useless if what you are after is creating files (or NOOP out if they exist). – Adrian Frühwirth Apr 10 '14 at 12:40
  • 1
    Don't forget that noclobber has not to be set so that > will overwrite an existing file. – Ouki Apr 10 '14 at 13:23
  • 1
    @Ouki AFAIK, setting that is not default behaviour and one could forget that it's set on one system and not another, potentially leading to trouble in the same way that creating an alias rm='rm -i' instead of alias rmi='rm -i' is a bad idea. – Agi Hammerthief Apr 10 '14 at 16:31
  • But you create an empty file. : >./file – mikeserv Apr 10 '14 at 22:00
  • 1
    @mikeserv, > .file, on a command line alone, will do that perfectly well without the :. – Charles Duffy Apr 11 '14 at 00:27
  • What about creating lock files? those are typically files that only need to exist but don't need any content. – Thomas BDX Apr 11 '14 at 01:54
  • 1
    @CharlesDuffy i suspect that is shell dependent. At my terminal i get a hung stream. – mikeserv Apr 11 '14 at 02:23
  • @Thomas, the Right Way to create lockfiles is to open a FD via redirection and then use fuser to attach a lock to that handle. If you just depend on the file existing, without an advisory lock associated, it's very hard to avoid race conditions (or cleanup difficulties). – Charles Duffy Apr 11 '14 at 04:02
  • @mikeserv, works with bash, dash, and busybox ash. What shell are you testing with? – Charles Duffy Apr 11 '14 at 04:03
  • @mikeserv, ahh. Not surprised, given that POSIX compliance is a non-goal for zsh. I don't believe the "no other stream gets dumped" thing is a real concern -- can you reproduce such a problem? (It would be a genuine issue for exec >file, but that's a different operation). – Charles Duffy Apr 11 '14 at 04:33
  • @mikeserv, section 2.9.1 of the "shell command language" provides by the case where a command consists of nothing but a redirection with the language (within step 2) "If any fields remain following their expansion" -- thus making the case where that "if" is not valid legal. Steps 1 and 3, relating to redirection, clearly still apply in that case. So -- failure to support this is, in fact, noncompliant with POSIX sh. – Charles Duffy Apr 11 '14 at 13:21
  • @mikeserv, ...and as >file redirects no command, how and why would you expect "no command" to read from stdin? Again, a reproducer for this purported behavior would be appreciated. – Charles Duffy Apr 11 '14 at 13:22
  • @CharlesDuffy - You are correct - in every shell I try (bash's sh, dash, bash) except zsh it makes no difference whether I use the :null or not. Still, the behavior is identical and exactly as expected when I use the : null in every shell. It seems to me a single : character - which also adds to clarity of purpose - is not much to ask if it means the difference between either piping a possibly unending stream of data into the disk or creating an empty file. – mikeserv Apr 11 '14 at 17:02
  • @mikeserv, POSIX behavior is clear on that point; no POSIX-compliant shell will "pipe a possibly unending stream of data" when used in that manner, since the redirection does not last past the completion of the (nonexistant) command's processing. That said, I do understand recommending a practice on the basis of improving compatibility with popular non-POSIX shells. – Charles Duffy Apr 11 '14 at 17:35
  • @mikeserv, I already did quote -- section 2.9.1, step 2. And bash is, in fact, a proper superset of POSIX sh. Certainly, it supports a very large number of features which POSIX does not require, but the places where it offers behavior which explicitly conflict with POSIX compliance (such as extglobs) are all off-by-default and require explicit enablement. – Charles Duffy Apr 11 '14 at 17:37
  • Bash's behavior in sh mode is a smaller superset, but still a superset. Both of these implement more features than the POSIX sh specification mandates -- and both of them comply with the spec, by implementing every feature that is mandated in the precise way in which it is mandated. How large of a superset something is is irrelevant; what's important for determining compliance is that it is in fact a superset. – Charles Duffy Apr 11 '14 at 17:48
  • I don't see anything unclear: "2. The words that are not variable assignments or redirections shall be expanded. If any fields remain following their expansion, the first field shall be considered the command name and remaining fields are the arguments for the command.
    1. Redirections shall be performed as described in Redirection." --

    thus, redirections are unconditionally performed, whether or not any command is given. It's about as clear as anything else in the spec.

    – Charles Duffy Apr 11 '14 at 17:51
  • Moreover, it's identical with the behavior of ksh88 (which acted in large part as the prototype for the POSIX.2 standard). – Charles Duffy Apr 11 '14 at 17:51
  • @mikeserv, indeed, Stephane makes the same point I make above quite clearly. All correct POSIX scripts are also correct bash scripts (not true with zsh), though not all bash scripts are correct POSIX scripts. – Charles Duffy Apr 11 '14 at 20:25
  • There you're actually right -- echo -n is, indeed, non-conformant. Sadly, it's a widely-accepted nonconformity -- I believe even ash implements it -- which is why I strongly suggest use of printf for anyone who wants to live in a moderately sane world. – Charles Duffy Apr 11 '14 at 21:24
  • @mikeserv Because you deleted your comment with the citation re: ambiguity, I haven't had a chance to read the quoted source in context and determine whether I agree with your interpretation on same. As such, I do not, at this point, acknowledge having made an incorrect statement on that point. (Also, I'm in the middle of a cross-country move, so it might be a few days before I can do my homework even if that cite is again provided). – Charles Duffy Apr 12 '14 at 12:56
  • 1
    @mikeserv ...moreover, I think there's value in letting readers follow the history of this thread and make up their own minds over whether echo -n is a substantial point of noncompliance in the context of comparison against a shell where string-splitting and glob expansion of unquoted expansions differs from POSIX-standardized behavior. As such, I'd rather not delete. – Charles Duffy Apr 12 '14 at 13:11
  • @CharlesDuffy I found the quote under the POSIX guidelines. And about deleting comments: this site is about qs and as. There's no chitchat. http://unix.stackexchange.com/tour – mikeserv Apr 12 '14 at 16:49
  • I disagree that creating empty files have no use. In some scripts I first check that a file does not have stale/invalid content, and then append to the file. Depending on the existing file I may truncate the existing file. Otherwise if the file doesn't exist, since I will be appending to it, I create a blank file in advance. The alternative would be to explicitly override the user's clobber settings, which I avoid doing as far as possible. – Johan Apr 22 '14 at 09:54
  • It is worth noting that there does exist commands specifically intended for making files. @terdon mentioned mktemp. Solaris also have mkfile which allows you to specify a size and whether to zero or create a sparse file. http://docs.oracle.com/cd/E23823_01/html/816-5166/mkfile-1m.html – Johan Apr 22 '14 at 09:57
  • There is also install. See my answer below. – Otheus May 30 '16 at 22:08
  • __init__.py is one counter-example – hello_there_andy Nov 27 '16 at 23:31
  • I think there is a valid case that improves readability to create the file before adding content like: touch git-build.properties

    echo "#useful comment" > git-build.properties

    – David W Dec 01 '16 at 14:31
16

Adrian Frühwirth's answer is right on. I just wanted to add that there is actually a command specifically written to create files: mktemp.

NAME
       mktemp - create a temporary file or directory

SYNOPSIS
       mktemp [OPTION]... [TEMPLATE]

DESCRIPTION
       Create a temporary file or directory, safely, and print its name.  TEM‐
       PLATE must contain at least 3 consecutive 'X's in last  component.   If
       TEMPLATE is not specified, use tmp.XXXXXXXXXX, and --tmpdir is implied.
       Files are created u+rw, and directories  u+rwx,  minus  umask  restric‐
       tions.

Granted, mktemp's job is not to create a file with a specific name, it is simply to create a file. However, as you've already been told, there are so many more efficient and elegant ways to create files with a given name that providing a command for that would be pointless.

That said, you also have truncate and fallocate both of whose essential purpose is to create files. They simply have a more sophisticated approach. There will never be a simple program that does what > file does since there is no way it would be better than > file.

terdon
  • 242,166
11

Most basic shell tools are not designed for any very specific purpose at all. Most basic shell tools are designed only to interact with others to achieve your purpose. Or maybe it should be said that most tools do only one very basic thing regardless of how they might be combined to achieve a goal.

: >./file

That creates an empty file. Or truncates an existing file as you will. You can:

set -o noclobber

to avoid any possibility of the latter case unless you:

: >|./file

You can get similar behavior to touch with:

: >>./file
: >>|./file

Except that : will not update a file's modtime because it isn't modified.

DEMO

mkdir test ; cd $_
touch touch.file 
: >null.file
echo >echo.file
ls -l

OUTPUT

-rw-r--r-- 1 mikeserv mikeserv 1 Apr 10 14:52 echo.file
-rw-r--r-- 1 mikeserv mikeserv 0 Apr 10 14:52 null.file
-rw-r--r-- 1 mikeserv mikeserv 0 Apr 10 14:52 touch.file

NOT TOUCH

: >>|./echo.file
ls -l 

OUTPUT

-rw-r--r-- 1 mikeserv mikeserv 1 Apr 10 14:52 echo.file
-rw-r--r-- 1 mikeserv mikeserv 0 Apr 10 14:52 null.file
-rw-r--r-- 1 mikeserv mikeserv 0 Apr 10 14:52 touch.file
mikeserv
  • 58,310
  • By default, echo adds \n at the end of the line. Try echo -n >echo-n.file (size=0) and echo -e >echo-e.file (size=1) – Thomas BDX Apr 11 '14 at 02:00
  • @Thomas 'A string to be written to standard output. If the first operand is -n, or if any of the operands contain a backslash ( '' ) character, the results are implementation-defined. On XSI-conformant systems, if the first operand is -n, it shall be treated as a string, not an option. The following character sequences shall be recognized on XSI-conformant systems within any of the arguments...' http://pubs.opengroup.org/onlinepubs/009604599/utilities/echo.html – mikeserv Apr 11 '14 at 02:04
  • Fair enough, thanks for the link, and my comment is not the point anyway – Thomas BDX Apr 11 '14 at 02:25
  • @Thomas What is the point? Combining a :null action with a redirection is the simplest means to create an empty file was my point. It is safe as well in that it guarantees no other data is streamed in. – mikeserv Apr 11 '14 at 02:28
  • 2
    Yes indeed and sorry, I meant that my comment was missing the point of your answer anyway, sorry about that. – Thomas BDX Apr 11 '14 at 02:30
  • 1
    An illustration of the Unix tendency to generalize is the fact that the command to display the contents of a file is called cat. Why have a command to display one file, when you could make one command to concatenate multiple files to standard output? – 200_success Apr 11 '14 at 02:54
1

The utility install is actually designed for creating files! You can pass the content of the file via /dev/stdin (in most cases, however, on most flavors of Linux, this requires that /proc is mounted) or provide another source file. You can set the ownership and permissions.

echo "New file" | install -o 0644 -m 452452 -g dumbass /dev/stdin /var/www/index.html

as a silly example.

Otheus
  • 6,138