72

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
  • 70,465

5 Answers5

75

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,236
  • 4
  • 48
  • 98
Byte Commander
  • 107,489
  • 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
29
mkdir -p parent/child && touch $_/file.txt
francis
  • 359
24

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
Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
  • 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 <filepath> – 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

1

I use The Fuck to make my life easier with this command. It's a CLI tool that corrects errors in previous console commands.

$ touch a/folder/that/does/not/exist/file
touch: cannot touch 'a/folder/that/does/not/exist/file': No such file or directory
$ fuck
mkdir -p a/folder/that/does/not/exist && touch a/folder/that/does/not/exist/file [enter/↑/↓/ctrl+c]
$ ls a/folder/that/does/not/exist/file
a/folder/that/does/not/exist/file