What you're doing is tricky. The normal way is to avoid this and just pass the array values as arguments. In order to have both options, you would have to use eval
:
#!/bin/bash
function populate_array () {
if [ "$#" -gt 0 ] ; then
# Enter array w/ elements as argument of executable
# Note the quotes, they are needed
array=("$@");
n=$#
else
# Invoke executable with no arg, enter array element later
# Read a string instead of an array and use eval to make it
# into an array. That way, you can use tricks like escaping
# spaces. You also need the -r option to protect the backslashes
# so that eval will see them.
read -r -p "Enter array elements separated by spaces: " string
eval array="( $(printf '%s\n' "$string") )"
n=${#array[@]}
fi
printf "%d array elements \n" "$n"
}
populate_array "$@"
while (("$n" > 0)) # while [ "$n" -gt 0 ] ALSO WORKS
do
printf "%s \n" "${array[$n-1]}"
n=$n-1
done
exit 0
You still need to escape the parentheses if you pass the array values as an argument since ( )
are reserved characters for bash. With that caveat, the script above should work as you expect:
$ foo.sh lkl1239 343.4l 3,344 \(34\) "lklk lkl" lkaa\ lkc
6 array elements
lkaa lkc
lklk lkl
(34)
3,344
343.4l
lkl1239
And
$ foo.sh
Enter array elements separated by spaces: lkl1239 343.4l 3,344 \(34\) "lklk lkl" lkaa\ lkc
6 array elements
lkaa lkc
lklk lkl
(34)
3,344
343.4l
lkl1239
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
I just found out how to delete such files witch special characters:
cd <directory with that file>
ls -ali
At the very left of the directory listing you see the ID of the inode of each file.
Delete your file via inode ID:
find . -inum <inode ID of your file> -exec rm -i {} \;
This worked fine for my issue. Hope this helps!