mkdir -p will create a directory; it will also make parent directories as needed.
Does a similar command exist for files, that will create a file and parent directories as needed?
mkdir -p will create a directory; it will also make parent directories as needed.
Does a similar command exist for files, that will create a file and parent directories as needed?
The install utility will do this, if given the source file /dev/null. The -D argument says to create all the parent directories:
anthony@Zia:~$ install -D /dev/null /tmp/a/b/c
anthony@Zia:~$ ls -l /tmp/a/b/c
-rwxr-xr-x 1 anthony anthony 0 Jan 30 10:31 /tmp/a/b/c
Not sure if that's a bug or not—its behavior with device files isn't mentioned in the manpage. You could also just give it a blank file (newly created with mktemp, for example) as the source.
No, it does not as far as I know. But you can always use mkdir -p and touch after each other:
f="/a/b/c.txt"
mkdir -p -- "${f%/*}" && touch -- "$f"
I frequently ran into this kind of situation, so I simply wrote a function in my .bashrc file. It looks like this
function create() {
arg=$1
num_of_dirs=$(grep -o "/" <<< $arg | wc -l)
make_dirs=$(echo $arg | cut -d / -f1-$num_of_dirs)
mkdir -p $make_dirs && touch $arg
}
So, when I want to create a file inside a path of non-existent directories, I will say
create what/is/it # will create dirs 'what' and 'is', with file 'it' inside 'is'
mkdir -p parent/child && touch "$_/file.txt"
$_ is a shell parameter, it expands to last argument of previous command. Example mkdir test && cd "$_" will create and cd into the directory test.
Add the following to your ~/.bashrc:
function mktouch() {
mkdir -p -- "$(dirname -- "$1")" && touch -- "$1"
}
Then reload bash then use it like mktouch your/path/file.txt.
It's possible to "fake it".
Rob Griffiths posted an article in 2007 entitled Easily Create Lots of New Folders on Macworld.com wherein he discussed using the xargs command to read in a list of files to create directories using mkdir.
xargs is capable of referencing a placeholder ({}) with the -I flag,
which contains the value for each argument passed to xargs. Here's the difference between with that flag, and without:
$ foo.txt bar.txt | xargs echo
$ => foo.txt bar.txt
$ foo.txt bar.txt | xargs -I {} echo {}
$ => foo.txt
$ => bar.txt
xargs is also capable of running arbitrary shell commands with the sh -c flag:
foo.txt bar.txt | xargs sh -c 'echo arbitrary command!'
We can combine these concepts with mkdir -p instead of mkdir and the concept in @ldx's answer to produce this:
$ cat files.txt | xargs -I {} sh -c 'f="{}" && mkdir -p -- "${f%/*}" && touch -- "$f"'
This command basically maps each filename in a line-separated list of files, chops off the file part, creates the directories with mkdir -p and then touches the filename in it's respective directory.
Say for instance my files.txt looks like this:
deeply/nested/foo/bar.txt
deeply/nested/baz/fiz.txt
cat files.txt produces deeply/nested/foo/bar.js deeply/nested/baz/fiz.txtdeeply/nested/foo/bar.js deeply/nested/baz/fiz.txt is piped to xargs-I {}, xargs will translate each argument to it's own command, so we now have:
deeply/nested/foo/bar.txtdeeply/nested/baz/fiz.txt&& combinator to group 3 commands that run sequentially - the first command stores the file in an environment variable (that gets re-used on the next file pass) using the placeholder we registered before, so we now have:
f=deeply/nested/foo/bar.txtf=deeply/nested/baz/fiz.txtmkdir -p, but we need to cut out the filename. Simple enough using '${f%/*}':
mkdir -p deeply/nested/foo/mkdir -p deeply/nested/baz/f variable in its entirety when we touch:
touch deeply/nested/foo/bar.txttouch deeply/nested/baz/fiz.txtI was going to suggest as it keeps it on one line, though setting the variable separately allows you to change it and rerun the command from the history pretty easily.
B="./make/this/path" && mkdir -p -- "$B" && touch -- "$B/file.txt"
$ mkdir -p foo/bar/baz.c && rmdir $_ && touch $_
This solution:
mkdir creates the full directory path, rmdir removes the last portion, and touch recreates the last portion as a file. The $_ pseudo-argument just inserts the last argument of the previous command.
As a bonus, this method completes Alt-. with $_, which is the newly-completed file name. Thus, a simple vim Alt-. will open the new file.
Note that filenames with spaces or other non-A-Za-zא-ת0-9._- characters should quote the argument shortcuts:
$ mkdir -p foo/bar/baz.c && rmdir "$_" && touch "$_"
I personally don't take this much care, but you should be aware of the limitation. Thank you to StéphaneChazelas for mentioning it in the comments.
dir=$(dirname "$f")
test -d $dir || mkdir -p "$dir"