149

I know you can do mkdir to create a directory and touch to create a file, but is there no way to do both operations in one go?

i.e. if I want to do the below when the folder other does not exist:

cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

Error:

cp: cannot create regular file `/my/other/path/here/cpedthing.txt': No such file or directory

Has anyone come up with a function as a workaround for this?

BuZZ-dEE
  • 6,075
  • 12
  • 66
  • 96
toop
  • 10,834
  • 24
  • 66
  • 87
  • 1
    Found this: http://stackoverflow.com/questions/1529946/linux-copy-and-create-destination-dir-if-it-does-not-exist – Bjørne Malmanger Feb 26 '12 at 12:16
  • If it's essential that the creation of the file and its directory be atomic, you would have to write a file system that offers this operation. It's not possible with the standard Linux file systems. – Peter G. Oct 10 '13 at 07:30
  • @toop I understand that this question is now a year and a half old, but several answers were recently merged into this. If you need to this type of thing very often, you may find [my answer](http://stackoverflow.com/a/19288855/119527) useful. (I'd argue more useful than the accepted answer, but I'm not begging for rep here :-) ) – Jonathon Reinhart Oct 23 '13 at 04:57
  • Found this: http://stackoverflow.com/a/8722721/29182 – Ziggy Dec 05 '13 at 09:33
  • @tdammers Q:"How do I do X?" A:"Here's how to do Y" – Henry Henrinson Jan 28 '16 at 09:52

11 Answers11

163

Use && to combine two commands in one shell line:

COMMAND1 && COMMAND2
mkdir -p /my/other/path/here/ && touch /my/other/path/here/cpedthing.txt

Note: Previously I recommended usage of ; to separate the two commands but as pointed out by @trysis it's probably better to use && in most situations because in case COMMAND1 fails COMMAND2 won't be executed either. (Otherwise this might lead to issues you might not have been expecting.)

evotopid
  • 5,288
  • 2
  • 26
  • 41
  • 18
    Probably better to use `&&`, as with `;`, if the first command fails, the second command will still run (and fail, too, as that directory does not exist yet). With `&&` if the first command fails, the second command does not run. – trysis Jun 07 '15 at 14:22
  • 15
    A short cut for the code example can be: `mkdir -p /my/other/path/here && touch $_/cpredthing.txt`. The `$_` expands to essentially the "last argument in the last command executed". – Sgnl Apr 19 '16 at 01:37
  • 4
    @Sgnl yours is arguably the correct answer. It is not just cleaner, it is less error-prone. – Choylton B. Higginbottom Aug 18 '17 at 16:45
  • 4
    I really wish `touch` took a `-p` parameter like `mkdir` does. – Ben174 Feb 19 '19 at 19:23
97

You need to make all of the parent directories first.

FILE=./base/data/sounds/effects/camera_click.ogg

mkdir -p "$(dirname "$FILE")" && touch "$FILE"

If you want to get creative, you can make a function:

mktouch() {
    if [ $# -lt 1 ]; then
        echo "Missing argument";
        return 1;
    fi

    for f in "$@"; do
        mkdir -p -- "$(dirname -- "$f")"
        touch -- "$f"
    done
}

And then use it like any other command:

mktouch ./base/data/sounds/effects/camera_click.ogg ./some/other/file
Community
  • 1
  • 1
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
31

Do it with /usr/bin/install:

install -D /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

when you don't have a source file:

install -D <(echo 1) /my/other/path/here/cpedthing.txt
Ivan Dives
  • 477
  • 5
  • 9
18

This is what I would do:

mkdir -p /my/other/path/here && touch $_/cpredthing.txt

Here, the $_ is a variable that represents the last argument to the previous command that we executed in line.

As always if you want to see what the output might be, you can test it by using the echo command, like so:

echo mkdir -p /code/temp/other/path/here && echo touch $_/cpredthing.txt

Which outputs as:

mkdir -p /code/temp/other/path/here
touch /code/temp/other/path/here/cpredthing.txt

As a bonus, you could write multiple files at once using brace expansion, for example:

mkdir -p /code/temp/other/path/here &&
touch $_/{cpredthing.txt,anotherfile,somescript.sh}

Again, totally testable with echo:

mkdir -p /code/temp/other/path/here
touch /code/temp/other/path/here/cpredthing.txt /code/temp/other/path/here/anotherfile /code/temp/other/path/here/somescript.sh
Sgnl
  • 1,808
  • 22
  • 30
14
#!/bin/sh
for f in "$@"; do mkdir -p "$(dirname "$f")"; done
touch "$@"
Javier
  • 60,510
  • 8
  • 78
  • 126
  • 1
    An anonymous user suggested (via edit) to use `dirname -z "$@" | xargs -0 mkdir -p` instead, for performance's sake. (Stop lurking, and join, for Pete's sake! ;-) – jpaugh Jan 23 '18 at 23:53
12

you can do it in two steps:

mkdir -p /my/other/path/here/
touch /my/other/path/here/cpedthing.txt
Jörg Beyer
  • 3,631
  • 21
  • 35
3

as I saw and test in a unix forum this solves the problem

ptouch() {
    for p in "$@"; do
        _dir="$(dirname -- "$p")"
        [ -d "$_dir" ] || mkdir -p -- "$_dir"
    touch -- "$p"
    done
}
Fabian Rios
  • 171
  • 1
  • 7
2
if [ ! -d /my/other ]
then
   mkdir /my/other/path/here
   cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt
fi
1

no need for if then statements... you can do it on a single line usign ;

mkdir -p /my/other/path/here;cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

-- or on two lines --

mkdir -p /my/other/path/here
cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

-- the -p prevents error returns if the directory already exists (which is what I came here looking for :))

1

In the special (but not uncommon) case where you are trying to recreate the same directory hierarchy, cp --parents can be useful.

For example if /my/long contains the source files, and my/other already exists, you can do this:

cd /my/long
cp --parents path/here/thing.txt /my/other
Todd Owen
  • 15,650
  • 7
  • 54
  • 52
-4

if you want simple with only 1 param snippet :

rm -rf /abs/path/to/file;  #prevent cases when old file was a folder
mkdir -p /abs/path/to/file; #make it fist as a dir
rm -rf /abs/path/to/file; #remove the leaf of the dir preserving parents 
touch /abs/path/to/file; #create the actual file
  • 3
    If you want to simply get rid of the last few hours'† work, gratitiously throw around some `rm -rf` commands. — †That is, _hours_, assuming you adhere to a sensible version control / backup policy... otherwise, it might well be months. – leftaroundabout May 16 '16 at 09:44
  • 3
    `rm -rf` should never be suggested without proper explanation and warnings. – Mausy5043 Oct 23 '18 at 08:38