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?

9
  • 11
    It's too bad that dsw didn't make it into POSIX. Jan 21, 2018 at 19:16
  • 12
    @MarkPlotnick: too bad the original dsw didn't make it into POSIX. Jan 21, 2018 at 20:09
  • 4
    I don't think you named it ctrl+C, you named it after the ascii character that is mapped to that keyboard shortcut, i.e. ETX (ascii 3) probably. Your console font has no glyph for that character, so it uses a generic substitution glyph "?".
    – jiggunjer
    Jan 22, 2018 at 8:12
  • 5
    emacs -nw -f dired gives a directory navigator. <kbd>D</kbd> deletes the file under the cursor after confirmation. Jan 22, 2018 at 9:10
  • 9
    @MatteoItalia It's too bad control characters in filenames and other idiotic ideas made it into POSIX...
    – pipe
    Jan 22, 2018 at 12:34

11 Answers 11

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.

5
  • 42
    This was probably how OP made their typo in the first place. V and C are right next to each other on the keyboard. Jan 22, 2018 at 10:38
  • 14
    Or they were trying to use the Windows clipboard on the bsd terminal.
    – Joel Coel
    Jan 24, 2018 at 3:12
  • 2
    @JoelCoel habits never die!
    – Mafii
    Jan 24, 2018 at 15:43
  • 2
    Interestingly, ^V^C does not work in the Zsh line editor; the quoted-insert widget (search the page for ^V) explicitly does not insert interrupt characters. Jakob's answer (using printf) may be a more portable way of supplying a control character in a shell argument.
    – Miles
    Jan 25, 2018 at 6:41
  • @StigHemmer: What can also happen is you press Ctrl-C in the middle of a command, then forget about this and copy-paste the command later.
    – user541686
    Jan 29, 2018 at 7:51
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!

10
  • 2
    Why not put -delete before -inum? Is this just a precaution in case you press enter prematurely or does the order of the arguments actually affect the outcome?
    – detuur
    Jan 22, 2018 at 15:55
  • 11
    @detuur: order affects outcome. See edit.
    – bishop
    Jan 22, 2018 at 16:03
  • 40
    Do not put -delete into the command, period, until you've run the command without -delete to check that it's finding what you want.
    – Kaz
    Jan 23, 2018 at 2:36
  • 2
    @Kaz will not help much with adding -delete in the center of command
    – RiaD
    Jan 23, 2018 at 12:44
  • 9
    @Kaz using -print instead of -delete makes a very good test. Jan 25, 2018 at 4:43
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.

8
  • 8
    select f in ?; do rm -i "$f"; break; done has all the benefits of -i, without the agony of having to answer no to leading undesirables or mistakenly answering yes to one you want to keep.
    – bishop
    Jan 22, 2018 at 3:35
  • 6
    In the OP's case it's a directory, not a file. rmdir ?/ will remove all empty single-character directories, and complain about the others being non-empty. Jan 22, 2018 at 5:30
  • 3
    @bishop: whoa, I didn't even know that select existed, pretty neat! Jan 22, 2018 at 6:48
  • @PeterCordes: wops, I didn't notice that we were talking about directories; I added -r (and ./ - it's always easy to forget) to my examples, as unfortunately rmdir doesn't support the -i flag. Still, I suppose that in this case the best way to go would be a combination of bishop's and your comment. Jan 22, 2018 at 6:53
  • 1
    @MatteoItalia select only exists in some shells, which is probably why you haven't run into it - scripts and solutions that are meant to be portable avoid it, so we're less likely to see it "in the wild".
    – mtraceur
    Jan 22, 2018 at 22:15
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.)

2
  • 2
    Also cat -v (plus man ascii) can help for the first part. Jan 21, 2018 at 20:20
  • 13
    ... or you use os.rmdir('\x03') directly from the Python shell.
    – moooeeeep
    Jan 22, 2018 at 7:56
15

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.

2
  • 4
    Or just about any other file manager. Jan 22, 2018 at 10:42
  • @StigHemmer of course, some do better than others for displaying certain filenames. Probably the answer could explain why MC is an optimal choice compared to a few select others. I wouldn't know, as I've never used it. Jan 28, 2018 at 6:21
7

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’
2
  • BTW if the shell is bash, $'\x03' is simpler than calling printf. The same for FreeBSD sh that is extended over POSIX shell with some tasty features.
    – Netch
    Jan 28, 2018 at 8:19
  • @Netch good point about bash's $'...', but I'd avoid useless conversion from octal to hexadecimal in general. E.g. what if the file were named '\111' (in stat output)? Would you still remove it using $'\x49'? Better use the same sequence as stat gave you: in the OP's case, rmdir $'\003'.
    – Ruslan
    Jan 28, 2018 at 8:27
6

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.

1
  • 1
    ^C is really early in the tab sequence so +1 for you.
    – joshudson
    Jan 23, 2018 at 23:49
5

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

5
  • 7
    Does this really seem easier to you than the accepted answer?
    – chicks
    Jan 21, 2018 at 18:27
  • 2
    @chicks: It's actually not such a bad answer. I've seen ^V^C not work so somebody might get stuck.
    – joshudson
    Jan 21, 2018 at 19:13
  • It isn't wrong per se, but it seems like a lot of extra work compared to the more direct solutions. Maybe I'm spoiled by Linux, but ^v has worked consistently me for ages.
    – chicks
    Jan 21, 2018 at 20:28
  • 6
    @chicks ^V need a specific knowledge while moving files around and removal of parent directory can be derived from basics.
    – Kondybas
    Jan 21, 2018 at 20:52
  • 5
    Ctrl+V is dangerously ambigous depending on your exact working environment ... some terminal emulators could interpret it as a paste. If your paste buffer contains the name of something you do not want to delete - and a newline, you could be looking at a problem. Jan 22, 2018 at 6:35
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.

2
  • 1
    You'd want to know which directories you want to recreate, and rmdir can tell you if you pass -v option to it (at least in GNU).
    – Ruslan
    Jan 22, 2018 at 12:09
  • @Ruslan: Not if you had other stale directories you no longer cared about, and removing them would be a bonus. You could look for empty directories with find -maxdepth 1 -type d -empty -ls Jan 22, 2018 at 12:59
-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.

2
  • 1
    In csh typing rmdir followed by <ctrl>C works? Really?! I'd expect it to behave differently, namely aborting the rmdir command and returning you to the commandline.
    – Mausy5043
    Jan 24, 2018 at 17:01
  • It will indeed. See the accepted answer about how to enter a ^C character on the command line.
    – Ale
    Jan 26, 2018 at 20:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .