Deleting Awkward Files

Deleting any file under Unix/Linux is usually a simple matter of using the “rm” command. Some files are more stubborn. If the file name contains special characters, or begins with a dash (“-“), it can be hard to get rid of:

bash-4.2$ ls -l
total 0
-rw-rw-r--. 1 james james 0 Aug 25 14:46 -a
-rw-rw-r--. 1 james james 0 Aug 25 14:46 logfile
-rw-rw-r--. 1 james james 0 Aug 25 14:45 some'file
bash-4.2$ rm some'file
> bash: unexpected EOF while looking for matching `''
bash: syntax error: unexpected end of file

A Few Alternatives

One obvious solution is to use a GUI. Highlight the awkward file in any file manager, hit the delete key, and it’s gone. But GUIs aren’t available everywhere. You may have only shell access to a server, for example.

Use Quotes

Putting quotes around the file often works:

bash-4.2$ rm "some'file"
bash-4.2$ ls -l
total 0
-rw-rw-r--. 1 james james 0 Aug 25 14:46 -a
-rw-rw-r--. 1 james james 0 Aug 25 14:46 logfile

but not for file names starting with “-“:

bash-4.2$ rm '-a'
rm: invalid option -- 'a'

File Names Beginning with “-“

A file like “-a” can be accidentally created, eg by a user who typed ls > -a filelist when they indented to say ls -a > filelist.

The shell treats files beginning with “-” as a special case. Quotes won’t work:

bash-4.2$ ls -l
total 0
-rw-rw-r--. 1 james james 0 Aug 25 14:46 -a
-rw-rw-r--. 1 james james 0 Aug 25 14:46 logfile
bash-4.2$
bash-4.2$ rm "-a"
rm: invalid option -- 'a'
Try `rm ./-a' to remove the file `-a'.
Try `rm --help' for more information.

Even with the quotes, the rm command thinks the file name is an option, and fails accordingly. rm ./-a works, at least on Linux:

bash-4.2$ rm ./-a
bash-4.2$ ls -l
total 0
-rw-rw-r--. 1 james james 0 Aug 25 14:46 logfile

Find it

There is an old “find” trick using inode numbers, documented for many years somewhere near the back of Unix Power Tools.

bash-4.2$ ls -li
total 0
166962 -rw-rw-r--. 1 james james 0 Aug 25 14:46 -a
166965 -rw-rw-r--. 1 james james 0 Aug 25 14:46 logfile
bash-4.2$ find . -inum 166962 -exec rm {} ;
bash-4.2$ ls -l
total 0
-rw-rw-r--. 1 james james 0 Aug 25 14:46 logfile

Handy, but rather a faff and not entirely risk free. If you have a large directory tree, the find might take a while to complete. It is also possible to delete the wrong file. If another file system is mounted somewhere under the current directory, “find” may cross the mount point, discover a second file with the same inode number and nuke it. Best run that find without the “rm” first, for safety, and with “-xdev” to stop any cross-mount-point shenanigans.

Use Perl

Perl has something to offer.

bash-4.2$ ls -l
total 0
-rw-rw-r--. 1 james james 0 Aug 25 15:17 -a
-rw-rw-r--. 1 james james 0 Aug 25 14:46 logfile
bash-4.2$ perl
unlink "-a"

bash-4.2$ ls
logfile

Meh.

The Proper Way

As demonstrated by my able colleague Neil Dixon, here is the best way to delete a file starting with “-“.

bash-4.2$ ls -l
total 0
-rw-rw-r--. 1 james james 0 Aug 25 15:20 -a
-rw-rw-r--. 1 james james 0 Aug 25 14:46 logfile
bash-4.2$ rm -- -a
bash-4.2$ ls -l
total 0
-rw-rw-r--. 1 james james 0 Aug 25 14:46 logfile

The double dash (“--“) tells rm that the arguments following are not options. They are therefore processed as file names and duly removed. More information is available somewhere in the getopt man pages. It works for other commands, and was used to create the example files above, thusly:

bash-4.2$ touch -- -a -b -c
bash-4.2$ ls -l
total 0
-rw-rw-r--. 1 james james 0 Aug 25 16:20 -a
-rw-rw-r--. 1 james james 0 Aug 25 16:20 -b
-rw-rw-r--. 1 james james 0 Aug 25 16:20 -c
bash-4.2$ rm -- -a -b -c

Leave a Reply

Your email address will not be published. Required fields are marked *