Saturday, July 25, 2009

Dashes and asterisks in linux filenames

This question was asked in an interview: "How do you delete a file that contain a leading dash/hyphen (-) in its filename ? ".

Well, in real time we rarely encounter such a scenario. But the fact is that dash is allowed to be used in a filename , but we don't usually use it at the beginning of the name. Now the problem with such a filename is that if you try to remove the file with rm command, rm will assume that the letters following the dash are command line options for the command and will throw a syntax either about a wrong option or missing operand. So the solution is to "escape" the dash at the beginning, but how can we do that? The first option is to use "--" which indicates that there are no more command line options to be read and the arguments following it should be considered as operands.

Let us try with an example;

safeer@enjoyfast-lx:~/temp$ ls
-file1
safeer@enjoyfast-lx:~/temp$ rm -file1
rm: invalid option -- 'l'
Try `rm ./-file1' to remove the file `-file1'.
Try `rm --help' for more information.

As you can see it is giving an invalid option error. Let us use the option terminator.

safeer@enjoyfast-lx:~/temp$ rm -- -file1
safeer@enjoyfast-lx:~/temp$ ls
safeer@enjoyfast-lx:~/temp$

By the way, did you notice the second line in the error message given above? Yeah, rm itself is suggesting a solution for your problem, use "./" . Giving an absolute or relative path before the filename prevents rm from interpreting the filename as an option to the command. Let us try it.

safeer@enjoyfast-lx:~/temp$ ls
-file1
safeer@enjoyfast-lx:~/temp$ rm ./-file1
safeer@enjoyfast-lx:~/temp$ ls
safeer@enjoyfast-lx:~/temp$

Now that solves the problem, but how do we create a a file with dash in name at the first place? We will have the same problem as rm with any command for creating a file, like touch,vi etc. We can use the same tricks as above here

safeer@enjoyfast-lx:~/temp$ touch -file1
touch: invalid option -- 'i'
Try `touch --help' for more information.
safeer@enjoyfast-lx:~/temp$ touch -- -file3
safeer@enjoyfast-lx:~/temp$ touch ./-file4
safeer@enjoyfast-lx:~/temp$ ls -l
total 0
-rw-r--r-- 1 safeer safeer 0 2009-07-25 00:01 -file3
-rw-r--r-- 1 safeer safeer 0 2009-07-25 00:01 -file4

Okay, now you have two files, how ill you delete them together? Let us try wild-card

safeer@enjoyfast-lx:~/temp$ rm *
rm: invalid option -- 'l'
Try `rm ./-file3' to remove the file `-file3'.
Try `rm --help' for more information.

This is because "*" expands to "-file3 -file4".So use the same trick again...

safeer@enjoyfast-lx:~/temp$ rm ./*
safeer@enjoyfast-lx:~/temp$ ls
safeer@enjoyfast-lx:~/temp$
safeer@enjoyfast-lx:~/temp$ touch ./-file{3,4}
safeer@enjoyfast-lx:~/temp$ ls
-file3 -file4
safeer@enjoyfast-lx:~/temp$ rm -- *
safeer@enjoyfast-lx:~/temp$ ls
safeer@enjoyfast-lx:~/temp$

Okay, enough fun with dash. Let us try asterisk ( * ) now.

Create a file with name "*" first.

safeer@enjoyfast-lx:~/temp$ touch *
safeer@enjoyfast-lx:~/temp$ ls
*
safeer@enjoyfast-lx:~/temp$ echo "Star" > *;echo "First" > file1;echo "Second" > file2
safeer@enjoyfast-lx:~/temp$ ls
* file1 file2

Now let us print the content of all the files.

safeer@enjoyfast-lx:~/temp$ cat *
Star
First
Second

safeer@enjoyfast-lx:~/temp$ cat * file1 file2
Star
First
Second
First
Second

In both the above cases * expands to the file list "* file1 file2". Now to print the contents of the file "*" let us try the same mechanisms.

safeer@enjoyfast-lx:~/temp$ cat -- *
Start
First
Second
safeer@enjoyfast-lx:~/temp$ cat ./*
Start
First
Second

It is not working because * will always expand unless it is escaped.

safeer@enjoyfast-lx:~/temp$ cat \*
Start

You can delete files the same way

safeer@enjoyfast-lx:~/temp$ rm \*
safeer@enjoyfast-lx:~/temp$ ls
file1 file2