The non-ASCII characters are not the problem, your shell can deal with å
perfectly well. The issue is that your file is not actually named å??
. If it were, rm 'å??'
or even rm å??
would have worked.
You assume it's å??
because that's what ls
shows, and that's a reasonable assumption, but ls
will show various things as ?
. For example:
$ mkdir "file å"\?\?" name.txt" "file å"$'\n'$'\n'" name.txt" "file å"$'\t'$'\t'" name.txt" "file å"$'\r'$'\r'" name.txt" "file å"$'\b'$'\b'" name.txt" "file å"$'\v'$'\v'" name.txt"
$ ls -l
total 24K
drwxr-xr-x 2 terdon users 4.0K Nov 8 13:02 file å?? name.txt
drwxr-xr-x 2 terdon users 4.0K Nov 8 13:02 file å?? name.txt
drwxr-xr-x 2 terdon users 4.0K Nov 8 13:02 file å?? name.txt
drwxr-xr-x 2 terdon users 4.0K Nov 8 13:01 file å?? name.txt
drwxr-xr-x 2 terdon users 4.0K Nov 8 13:02 file å?? name.txt
drwxr-xr-x 2 terdon users 4.0K Nov 8 13:02 file å?? name.txt
As you can see above, newlines, tabs, carriage returns, bells and vertical tabs (among others) are all shown as ?
. Only the first file/directory of the ones created above actually has ?
in its name. We can confirm this with ls -b
:
$ ls -lb
total 24
drwxr-xr-x 2 terdon users 4096 Nov 8 13:02 file\ å??\ name.txt
drwxr-xr-x 2 terdon users 4096 Nov 8 13:02 file\ å\b\b\ name.txt
drwxr-xr-x 2 terdon users 4096 Nov 8 13:02 file\ å\t\t\ name.txt
drwxr-xr-x 2 terdon users 4096 Nov 8 13:01 file\ å\n\n\ name.txt
drwxr-xr-x 2 terdon users 4096 Nov 8 13:02 file\ å\v\v\ name.txt
drwxr-xr-x 2 terdon users 4096 Nov 8 13:02 file\ å\r\r\ name.txt
So, you can either run ls -b
to get the right file name and then use ANSI C quoting to rename it:
mv å$'\r'$'\r' newname
Alternatively, you can use a glob to match all files/directories whose name starts with file å
(note: this will only work if you just have one) :
mv "file å*" newname
Or, rename all files/directories whose name contains non alphanumeric characters (again, only useful for cases where you have a single such case):
shopt -s extglob ## turn on extended globbing
mv !(*([[:graph:]])) newname
The strange !(*([[:graph:]]))
needs some explaining. extglob
enables extended globbing which lets us use !(foo)
to match "not foo". The [[:graph:]]
character class matches all printable characters (not tabs, newlines etc.) Therefore, the negated match !(*([[:graph:]]))
will match all file/dirnames with non-printing characters.
If you need to deal with more than one such case, use a loop. Something like:
for dir in !(*([[:graph:]])); do
mv "$dir" "${dir//[^[:graph:]]/_}";
done
The ${dir//[^[:graph:]]/_}
is the directory name with all non-printing characters replaced by _
. The problem with this approach is that you can have different source directories which will end up with the same name (e.g. foo\n
and foo\t
will both become foo_
). If that is a problem, just rename using a counter as well:
a=0; for dir in !(*([[:graph:]])); do
((a++));
mv "$dir" "${dir//[^[:graph:]]/_}$a"
done
That would result in:
drwxr-xr-x 2 terdon users 4096 Nov 8 13:08 file_å___name.txt1
drwxr-xr-x 2 terdon users 4096 Nov 8 13:08 file_å___name.txt2
drwxr-xr-x 2 terdon users 4096 Nov 8 13:08 file_å___name.txt3
drwxr-xr-x 2 terdon users 4096 Nov 8 13:08 file_å??_name.txt4
drwxr-xr-x 2 terdon users 4096 Nov 8 13:08 file_å___name.txt5
drwxr-xr-x 2 terdon users 4096 Nov 8 13:08 file_å___name.txt6
Best Answer
You can usually use
--
to indicate the end of command options. So:ls -- -*
(with the perl-based
rename
command)rename -n 's/^-//' -- -*
Remove the
-n
once you are happy that it is doing the right thing.See also: