mkdir -p for files
Solution 1
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.
Solution 2
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"
Solution 3
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'
Solution 4
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
.
Solution 5
It's possible to "fake it".
First, some required theory:
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!'
Combining the Concepts:
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 touch
es the filename in it's respective directory.
Here's a breakdown of what happens in the above command:
Say for instance my files.txt
looks like this:
deeply/nested/foo/bar.txt
deeply/nested/baz/fiz.txt
-
cat files.txt
producesdeeply/nested/foo/bar.js
deeply/nested/baz/fiz.txt
-
deeply/nested/foo/bar.js
deeply/nested/baz/fiz.txt
is piped toxargs
- because we used
-I {}
,xargs
will translate each argument to it's own command, so we now have:deeply/nested/foo/bar.txt
deeply/nested/baz/fiz.txt
- we then run a shell command that uses the
&&
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.txt
f=deeply/nested/baz/fiz.txt
- we now have a variable we can pass to
mkdir -p
, but we need to cut out the filename. Simple enough using'${f%/*}'
:mkdir -p deeply/nested/foo/
mkdir -p deeply/nested/baz/
- and then we just re-reference the
f
variable in its entirety when wetouch
:touch deeply/nested/foo/bar.txt
touch deeply/nested/baz/fiz.txt
Related videos on Youtube
Comments
-
user1730706 almost 2 years
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?
-
Admin over 11 yearsNot that I am aware of.. but you could just do mkdir -p /path/to/make && touch /path/to/file... Which would make an empty file in that new directory structure you created all as needed.
-
Admin over 11 years@Kansha combine that with
dirname
andbasename
and we'll only need the single argument; profit! :) -
Admin over 11 yearsAye, good call.
-
-
derobert over 11 yearsThe
test
isn't needed;mkdir -p
doesn't do anything if the dir already exists. Doesn't even return an error. -
user over 11 yearsAnd of course, this only creates the directory.
-
user1730706 over 8 yearsYou have all this explaination for what is essentially
cat files.txt | xargs -I {} sh -c 'f="{}" && mkdir -p -- "${f%/*}" && touch -- "$f"'
, which has UUOC, then you subshell into xargs which subshells back into the shell, when awhile read
loop makes more sense -
razorbeard over 8 yearsI'll admit I'm not the most clued up on *nix commands - I don't even know what UUOC is - but I fail to see how this is an awful answer. It is researched, tested and is a working solution to your original question. It's constructive (unlike your rather rude comment). Please, if you feel that I've done something irresponsible here that I should not have, then elaborate further - explain why. I don't care much for opinionated debate that has no substance.
-
user1730706 over 8 yearsMy last comment explains it perfectly. Your entire answer could be better written as
while read f; do mkdir -p "$(dirname "$f")"; touch "$f"; done < files.txt
. The fact that you cant do a 10 second internet search for UUOC is also telling -
ecoologic about 5 yearsMy man! - thank you, I called it
touchp
, likemkdir -p