34

I've tried

rm -- -
rm "-"
rm "\-"
rm \-

Gave Perl a shot

~$ perl -e '$junk = glob("-"); chomp $junk; print "$junk\n"; `rm $junk`;'
-
rm: cannot remove `-': No such file or directory

...and...

~$ perl -e '$junk = glob("-"); chomp $junk; print "$junk\n"; `mv $junk newfile.garbage`;'
-
mv: cannot stat `-': No such file or directory

Any assistance would be much appreciated, wise folks.

Sathyajith Bhat
  • 61,504
  • 38
  • 179
  • 264
jgrundstad
  • 353
  • 3
  • 8
  • Out of curiousity, how did it get there? – Petey B Oct 17 '11 at 17:09
  • 2
    It was the result of a poorly constructed wget: "wget -q -O – http://www.someserver.org/s/ip" –  Oct 17 '11 at 17:10
  • 53
    Reminds me of the time a colleague created a file named * . This story did not end well. – David Heffernan Oct 17 '11 at 17:14
  • What `rm` version are you using (`rm --version`)? `rm -` works fine with GNU coreutils 8.5. – Lekensteyn Oct 17 '11 at 17:59
  • fyi, zipping from a pipe also produces a file with the same name.. although I don't recall it being difficult to delete. – user606723 Oct 17 '11 at 18:52
  • From your reply below, I would say there is no such file. – runrig Oct 17 '11 at 20:31
  • First thing I'd do is `ls` to a file and then use a hex editor on the file to see what the name really is. Then write a simple Java program to do File.delete of the named file. – Daniel R Hicks Oct 18 '11 at 03:38
  • 2
    Another variant: `rm ./-` – user Oct 18 '11 at 06:35
  • [Files starting with a dash, -](https://superuser.com/q/120078/241386), [How to open files with forward dash in linux](https://superuser.com/q/603792/241386), [How to create a file which is named like a command line argument?](https://superuser.com/q/600066/241386), [Recursively rename all files whose name starts with a dash](https://askubuntu.com/q/882773/253474), [Can't rename a file the name of which starts with a hyphen](https://superuser.com/q/510337/241386), [How do I delete a file whose name begins with “-” (hyphen a.k.a. dash or minus)?](https://unix.stackexchange.com/q/1519/44425) – phuclv Aug 20 '18 at 05:39

12 Answers12

61

This used to be posted in the Usenet FAQs for Unix—I see it is in the GNU Core Utility FAQs. There were at least five different methods, but this works well:

$ rm ./-

If a filename contains untypeable characters, then use:

$ rm -i *

The -i flag asks for confirmation for each file if it should be removed or not.

wallyk
  • 1,348
  • 10
  • 18
39

Removing a file whose names starts with - is a FAQ, but it looks like you've got a different problem.

Of the solutions you mentioned in the question:

rm -- -

That should work.

rm "-"

That's no different from rm -. The quotes are stripped by the shell, and the rm command just sees the single hyphen as an argument. Quotation marks are useful for escaping shell metacharacters; the hyphen is special to rm, not to the shell.

rm "\-"

The quotation marks escape the backslash, so this attempts to remove a file whose name consists of two characters, a backslash and a hyphen.

rm \-

This is just like rm "-", equivalent to rm -.

As it happens, at least with the GNU coreutils version of rm, rm - actually removes (or attempts to remove) a file whose name consists of just a hyphen. If your file had that name, it would be gone by now. I conclude that your file has a name that only looks like a hyphen.

ls | cat -A

should give an idea of what it's really called.

Here's a Perl script I just threw together that will prompt you for each file in the current directory and ask whether to remove it. Offered without warranty, but I've tested it briefly.

#!/usr/bin/perl

use strict;
use warnings;

$| = 1;

opendir my $DIR, '.' or die ".: $!\n";
my @files = sort grep { -f $_ } readdir $DIR;
closedir $DIR;

foreach my $file (@files) {
    print "Remove $file? ";
    my $answer = scalar <>;
    if ($answer =~ /^[Yy]/) {
        unlink $file or warn "$file: $!\n";
    }
    elsif ($answer =~ /^[Qq]/) {
        exit 0;
    }
}

EDIT: A less elaborate solution: if the file's name is just one character, then rm ? should remove it (along with any other such files).

Keith Thompson
  • 5,075
  • 2
  • 25
  • 33
19

If you want something safer...

Try using a combination of ls and find (this works for any file you have permission to remove)

The '-i' parameter will give you the inode number for each directory entry ls -li

27 ----------  1 owner  group       3981 Oct 11 04:42 ?????

Once you have the inode number...

find . -inum **27** -exec rm -i {} \;
Sathyajith Bhat
  • 61,504
  • 38
  • 179
  • 264
Sam
  • 191
  • 2
  • 2
    +1 as this is a great general answer for these problems. By the way theres no need to used -exec rm in recent find's, just use -delete – Sirex Oct 17 '11 at 21:22
  • 2
    @Sirex - I think the point of `-exec rm -i {}` is the `-i` to prompt for removal. I'm looking at `man find` and don't see any way to do that. – Stephen P Oct 18 '11 at 00:41
  • oh yes, in this case. was more of a tip. – Sirex Oct 18 '11 at 21:02
13

Give rm ./- a try.

The - is a flag to start a flag argument. If you start the argument with anything but a -, in this case /, it will assume it's the file name. Which is what you wish.

And since file and ./file are the same file, it will target the file named - via ./-.

slhck
  • 223,558
  • 70
  • 607
  • 592
Petey B
  • 696
  • 8
  • 21
  • 8
    Rather than typing 30 characters, perhaps it would have been more useful to explain why the / helps parse correctly – Ivo Flipse Oct 17 '11 at 20:42
  • @gcb Thanks for the proposed edit. I added code markup to that, so it would be easier to read. – slhck Oct 18 '11 at 09:33
7

Try:

$ ls -b

to see if the filename has unprintable characters.

Gaff
  • 18,569
  • 15
  • 57
  • 68
Noel Yap
  • 181
  • 4
  • Why the downvote? Given the [followup](http://superuser.com/questions/347505/how-do-i-remove-a-file-in-linux-whose-name-looks-like-its-only-a-hyphen-as-in/347544#347544), this sounds like a very good suggestion. – Ilmari Karonen Oct 18 '11 at 11:18
7

Not as geeky as most other answers, but I would fire up an instance of mc, midnight commander, and just select and delete the file.

johanvdw
  • 170
  • 4
  • +1 for cleverly side-stepping the issue - and that without even resorting to a GUI program. – sleske Jan 04 '12 at 11:14
6

Not that it should be necessary to use perl here, but this should work:

perl -e 'unlink "-"'

or to see what any error with the above might be:

perl -e 'unlink "-" or die "Err: $!"'
runrig
  • 161
  • 4
  • This method has the advantage that there are no special characters to worry about (other than string quoting issues). – Kevin Reid Oct 17 '11 at 18:33
3

I have had luck using GNOME's Nautilus to remove badly named files. Are you running an X-server? I'm sure other file browsers would work too.

Joel Berger
  • 131
  • 3
3

If

rm -- -

didn't work, the file name is not "just a hyphen". If no other files have a hyphen in them, you could try

perl -E'for (@_) { if (/-/) { unlink($_) or die $! } }' -- *
ikegami
  • 224
  • 1
  • 11
1

So far I get a "No such file or directory" for every method posted so far:

rm ./-
rm -- -
mv "-" test.txt
rm -rf '-' <-- this gives no error, but doesn't work
perl -e 'unlink "-";'  <--also no error, doesn't work.

It appears I've got rm version 7.4. I'll try upgrading and re-attempting these suggestions. Thanks everyone for helping.

jgrundstad
  • 353
  • 3
  • 8
  • 1
    I'm guessing that there is no such file or directory, and perhaps the file name also contains some invisible character(s). (and you could get about the same error message in perl with 'unlink "-" or die "Err: $!"'). Try "ls -b" to see what the real filename is. – runrig Oct 17 '11 at 20:27
1

I'm very fond of using dired mode in emacs for this kind of thing -- just "open" the directory in emacs. You can easily select files and mark them for deletion.

Another poster suggested using midnight commander; this is pretty much the same idea, but if you're already an emacs user it's perhaps more convenient.

0

Should be able to do rm -f '-' worked for me in cygwin

For that matter, rm - also seems to work on red hat.

Tamara Wijsman
  • 57,083
  • 27
  • 185
  • 256
Lucas
  • 113
  • 7