129

I made a typo:

$ history
169 9:34    la /usr/local/etc/
170 9:35    sudo mkdir ^C
171 9:36    sudo mkdir /usr/local/etc/dnsmasq.d

Now I have a file that is called ^C (ctrl+C)!! When I use ls I just see a questionmark (probably due to the locale?)

% ls -al
total 60
drwxr-xr-x  2 root   wheel    512 Jan 21 09:35 ?        <- this one
drwxr-xr-x  5 admin  wheel    512 Jan 21 16:24 .
drwxr-xr-x  3 root   wheel    512 Jan 20 14:29 ..
-rw-r--r--  1 admin  nobody  1114 Jan 20 19:10 .cshrc
-rw-------  1 admin  wheel   6002 Jan 21 15:27 .history
-rw-r--r--  1 admin  nobody   182 Jan 20 14:29 .login
-rw-r--r--  1 admin  nobody    91 Jan 20 14:29 .login_conf
-rw-------  1 admin  nobody   301 Jan 20 14:29 .mail_aliases
-rw-r--r--  1 admin  nobody   271 Jan 20 19:04 .mailrc
-rw-r--r--  1 admin  nobody   726 Jan 20 19:05 .profile
-rw-------  1 admin  nobody   212 Jan 20 14:29 .rhosts
-rw-r--r--  1 admin  nobody   911 Jan 20 19:06 .shrc
drwx------  2 admin  nobody   512 Jan 20 15:05 .ssh
drwxr-xr-x  2 admin  wheel    512 Jan 20 19:08 bin

and

% ls -i
3611537 ?   3611534 bin

I want to remove this file. I try mv and when using tab-completion it shows me:

% mv
^C/  bin/

Obviously I can't type a ^C :-/ How do I remove this file?

Mausy5043
  • 1,367

11 Answers11

192

^V (ctrl+v) works as a kind of escape sequence for the next key-press, inserting the associated value instead of taking whatever action that would normally be associated.

Making use of this, ^V^C (ctrl+v, ctrl+c) ought to work for entering your difficult filename in the terminal.

92

You may also remove the file by inode:

$ ls -i1
290742 foo
293246 ^C
$ find . -inum 293246 -delete

Whatever you do, for God's sake, do not put -delete before -inum:

$ touch foo bar baz quux
$ find . -name '*u*' -delete
$ ls
bar baz foo
$ find . -delete -name 'b*'
find: `./baz': No such file or directory
find: `./bar': No such file or directory
$ ls
$ 

Congratulations, you just wiped out all your files. With find, argument order matters!

bishop
  • 1,103
32

Another option is to use rm -ri ./*; rm will ask you before deleting any file and directory, so you just need to reply y to the "bad" file, and n to all the others.

Actually, in your case you can even cut down the number of replies needed by doing rm -ri ./?, as your "bad" file is just one character long.

23

One option is to look up the file name with something other than ls. If you know it was produced by a verbatim Ctrl+C, you can find the ASCII character produced using a table of control characters, or with a more friendly interface like the one provided by Python:

>>> import os
>>> os.listdir('.')
['\x03', ...]

Another option would be to look at a hex dump of the output of ls, using e.g. hexdump.

Then you can delete the file with (for example) this bash command:

rmdir "$(printf '\x03')"

(The double quotes are only needed if the character you're trying to print is in your IFS variable, such as \x20 or \x0A, but it's a good habit to quote command substitutions unless you know you want the shell to perform field splitting, etc.)

Jakob
  • 331
16

Often in this kind of situations it is easy to come up with a wildcard pattern that matches the relevant file.

In your case, this would be simply ? (matching all file names with precisely one character).

Just check that it really matches what you want:

ls -ld ?

And then remove the directory:

rmdir ?

You can also combine this with tab completion. You can type

rmdir ?

and press tab, and e.g. in bash it will be replaced by

rmdir ^C/

and you can then hit enter and it does what you want.

11

You can use Midnight Commander (mc) to delete the file - just select with up/down buttons and press F8.

I did that occasionally when file names had strange characters due to encoding.

filo
  • 431
8

Yet another way: use stat to get an escaped representation of the directory name:

$ stat *|grep File:
  File: ‘\003’

Now you know a representation of the file name, so you can remove the file by name using printf:

$ rmdir -v "$(printf '\003')"
rmdir: removing directory, ‘\003’

Or, if you're using bash, you can avoid printf:

$ rmdir -v $'\003'
rmdir: removing directory, ‘\003’
Ruslan
  • 243
7

A solution that has worked for me is:

rm ./[Tab][Tab][Tab]...

to cycle through the available files until I find the one I want to remove.

But you do need to have the necessary settings in your shell for that to work.

5

The easiest way is to move everything to the temporary directory and then rm -r DIRNAME.

Kondybas
  • 7,110
1

If it's the only empty directory (or you don't care about removing other empty directories), use rmdir */. You will get error messages from rmdir about not being able to remove non-empty directories, but that's fine. GNU rmdir supports --ignore-fail-on-non-empty, or you could 2>/dev/null.

The trailing / makes the glob only match directory names.

You can check ahead of time what empty directories exist under the current one using
find -maxdepth 1 -type d -empty -ls. (And you can change the -ls to -delete if you want).

You could use a more-specific glob expression like rmdir [^A-Za-z0-9._]/ to match directories that start with a non-alphanumeric or underscore filename. I also included ., but glob expressions don't match . normally anyway.


As others have pointed out, you can limit it to single-character names with a glob of ?: rmdir ?/

rmdir doesn't have a -i option the way rm does, presumably because empty directories are usually not valuable and can just be recreated.

-1

Before doing anything risky, try this first:

rmdir -- ^C

In general -- is a delimiter telling the command no -o ptions will follow, but it will also allow for weird characters to be not interpreted as something else.

Another usage example is whois -r -- "-r OBJECT-RIPE"

(-r is a shortcut for ripe, but in the ripe whois also a parameter)

If it doesn't work at first try, then maybe try rmdir -- "^C"

But at my csh shell I don't need any of it, simply rmdir ^C already works for me.