63

I know that touch command creates a file:

touch test1.txt

but how I can create a file and its full path?

for example my desktop contains nothing:

~/Desktop/$ ls
~/Desktop/$

and I want to create 1.txt in ~/Desktop/a/b/c/d/e/f/g/h/1.txt. Can I do this with a simple command like:

$ touch ~/Desktop/a/b/c/d/e/f/g/h/1.txt

instead of create full path manually and then create the file?

Zanna
  • 69,223
  • 56
  • 216
  • 327
M.A. Heshmat Khah
  • 867
  • 2
  • 9
  • 17

4 Answers4

69

touch is not able to create directories, you need mkdir for that.

However, mkdir has the useful -p/--parents option which creates a full directory structure.

From man mkdir:

   -p, --parents
          no error if existing, make parent directories as needed

So the command you need in your specific situation is:

mkdir -p ~/Desktop/a/b/c/d/e/f/g/h/ && touch ~/Desktop/a/b/c/d/e/f/g/h/1.txt

If you think you will need this more often and don't want to type the path twice every time, you can also make a Bash function or a script for it.

  • Bash function (append this line to ~/.bashrc to persitently have it available to your user, otherwise it will vanish again when you exit your terminal):

    touch2() { mkdir -p "$(dirname "$1")" && touch "$1" ; }
    

    It can be simply used like this:

    touch2 ~/Desktop/a/b/c/d/e/f/g/h/1.txt
    
  • Bash script (store it in /usr/local/bin/touch2 using sudo to make it available for all users, else in ~/bin/touch2 for your user only):

    #!/bin/bash
    mkdir -p "$(dirname "$1")" &&
        touch "$1"
    

    Don't forget to make the script executable using chmod +x /PATH/TO/touch2.

    After that you can also run it like this:

    touch2 ~/Desktop/a/b/c/d/e/f/g/h/1.txt
    
wjandrea
  • 14,109
  • 4
  • 48
  • 98
Byte Commander
  • 105,631
  • 46
  • 284
  • 425
  • can I edit original `touch ` command and add switch `-p` to it? – M.A. Heshmat Khah Jul 20 '16 at 12:35
  • 3
    @HeshmatKhah It should be possible, but it is not recommended to shadow system executables with your own scripts or functions. You could use the name `touch-p` (no space!) instead of `touch2`, if you prefer the "p", but I would not attempt to replace the original command. – Byte Commander Jul 20 '16 at 15:11
  • 2
    Note that you can use suffix removal instead of `dirname` as well , i.e. you could do `mkdir -p "${1%/}" && touch "$1"` , same as https://askubuntu.com/a/928544/295286 – Sergiy Kolodyazhnyy Jun 23 '17 at 18:59
  • Extra question: if I try to execute `touch2` from another script as `bash x.sh` or `./x.sh`, then bash says `touch2: command not found`. What is the root cause? How to fix? UPD: I've already tried: `#!/bin/bash -i`, `shopt -s expand_aliases`, `source ~/.bashrc`. Nothing worked for me. So, I've had to put `touch2() { mkdir -p "$(dirname "$1")" && touch "$1" ; }` directly into the `x.sh`. – pmor May 20 '23 at 10:15
24
mkdir -p parent/child && touch $_/file.txt
francis
  • 309
  • 3
  • 6
23

One can use install command with -D flag.

bash-4.3$ install -D /dev/null mydir/one/two

bash-4.3$ tree mydir
mydir
└── one
    └── two

1 directory, 1 file
bash-4.3$ 

If we have multiple files, we might want to consider using a list of items(note, remember to quote items with spaces), and iterating over them:

bash-4.3$ for i in mydir/{'subdir one'/{file1,file2},'subdir 2'/{file3,file4}} ; do 
> install -D /dev/null "$i"
> done
bash-4.3$ tree mydir
mydir
├── one
│   └── two
├── subdir 2
│   ├── file3
│   └── file4
└── subdir one
    ├── file1
    └── file2

Or alternatively with array:

bash-4.3$ arr=( mydir/{'subdir one'/{file1,file2},'subdir 2'/{file3,file4}} )
bash-4.3$ for i in "${arr[@]}"; do  install -D /dev/null "$i"; done
bash-4.3$ tree mydir
mydir
├── one
│   └── two
├── subdir 2
│   ├── file3
│   └── file4
└── subdir one
    ├── file1
    └── file2
WinEunuuchs2Unix
  • 99,709
  • 34
  • 237
  • 401
Sergiy Kolodyazhnyy
  • 103,293
  • 19
  • 273
  • 492
  • 7
    WIth this approach, the new file gets executable permissions by default. To give it the same permissions it would get with touch, one can use `install -m 644 -D /dev/null ` – ricab Sep 10 '19 at 09:21
4

For this purpose you can create your own function, example below:

$ echo 'mkfile() { mkdir -p "$(dirname "$1")" && touch "$1" ;  }' >> ~/.bashrc
$ source ~/.bashrc
$ mkfile ./fldr1/fldr2/file.txt

First we insert a function to the end of ~/.bashrc file using echo command. The -p flag in function allows to create the nested folders, such as fldr2 from our example. Finally we update the file with source command and eventually execute recently created mkfile command

Purkhalo Alex
  • 319
  • 2
  • 7