You are right, /
is not valid, as is the null-byte \0
. There is no way around that limitation (besides file system hacking).
All other characters can be used in file names, including such surprising characters as a newline \n
or a tab \t
. There are many ways to enter them so that the shell does not understand them as special characters. I will give just a pragmatic approach.
You can enter most of the printable characters by using the singlequote '
to to quote them:
date > 'foo!bar["#$%&()*+,-.:;<=>?@[\]^_`{|}~'
Of course, you cannot enter a singlequote this way, but for this you can use the doublequote "
:
date > "foo'bar"
If you need to have both, you can end one quotation and start another:
date > "foo'bar"'"bloh'
Alternatively you also can use the backslash \
to escape the special character directly:
date > foo\"bar
The backslash also works as an escaper withing doublequotes, it does not work that way within singlequotes (there it is a simple character without special meaning).
If you need to enter non-printable characters like a newline, you can use the dollar-singlequote notation:
date > $'foo\nbar'
This is valid in bash, but not necessarily in all other shells. So take care!
Finally, it can make sense to use a variable to keep your strange name (in order not to have to spell it out directly:
strangeName=$(xxd -r <<< "00 41 42 43 ff 45 46")
date > "$strangeName"
This way you can keep the shell code readable.
BUT in general it is not a good idea to have such characters in file names because a lot of scripts cannot handle such files properly.
To write scripts fool-proof is not easy. The most basic rule is the quote variable usage in doublequotes:
for i in *
do
cat "$i" | wc -l
done
This will solve 99% of the issues you are likely to encounter.
If you are using find
to find directory entries which can contain special characters, you should use printf0
to separate the output not by spaces but by null-bytes. Other programs like xargs
often can understand a list of null-byte separated file names.
If your file name can start with a dash -
it often can be mistaken as an option. Some programs allow giving the special option --
to state that all following arguments are no options. The more general approach is to use a name which does not start with a dash:
for i in *
do
cat ./"$i" | wc -l
done
This way, a file named -n
will not run cat -n
but cat ./-n
which will not be understood as the option -n
given to cat
(which would mean "number lines").