So Im removing special characters from filenames and replacing with spaces. I have all working apart from files with single backslashes contained therein. Note these files are created in the Finder on OS X
old_name="testing\this\folder"
new_name=$(echo $old_name | tr '<>:\\#%|?*' ' ');
This results in new_name being "testing hisolder" How can I just removed the backslashes and not the preceding character?
This results in new_name being "testing hisolder"
This string looks like the result of echo -e "testing\this\folder"
, because \t
and \f
are actually replaced with the tabulation and form feed control characters.
Maybe you have an alias like alias echo='echo -e'
, or maybe the implementation of echo
in your version of the shell interprets backslash escapes:
POSIX does not require support for any options, and says that the behavior of ‘echo’ is implementation-defined if any STRING contains a backslash or if the first argument is ‘-n’. Portable programs can use the ‘printf’ command if they need to omit trailing newlines or output control characters or backslashes.
(from the info page)
So you should use printf
instead of echo
in new software. In particular, echo $old_name
should be replaced with printf %s "$old_name"
.
There is a good explanation in this discussion, for instance.
No need for printf
As @mklement0 suggested, you can avoid the pipe by means of the Bash here string:
tr '<>:\\#%|?*' ' ' <<<"$old_name"
Ruslan's excellent answer explains why your command may not be working for you and offers a robust, portable solution.
tl;dr:
sh
rather than bash
(even though on macOS sh
is Bash in disguise), or you had shell option xpg_echo
explicitly turned on. printf
instead of echo
for portability.In Bash, with the default options and using the echo
builtin, your command should work as-is (except that you should double-quote $old_name
for robustness), because echo
by default does not expand escape sequences such as \t
in its operands.
However, Bash's echo
can be made to expand control-character escape sequences:
shopt -s xpg_echo
sh
or with the --posix
option (which, among other options and behavior changes, activates xpg_echo
)Thus, your symptom may have been caused by running your code from a script with shebang line #!/bin/sh
, for instance.
However, if you're targeting sh
, i.e., if you're writing a portable script, then echo
should be avoided altogether for the very reason that its behavior differs across shells and platforms - see Ruslan's printf
solution.
As an aside: perhaps a more robust approach to your tr
command is a whitelisting approach: stating only the characters that are explicitly allowed in your result, and excluding other with the -C
option:
old_name='testing\this\folder'
new_name=$(printf '%s' "$old_name" | tr -C '[:alnum:]_-' ' ')
That way, any characters that aren't either letters, numbers, _
, or -
are replaced with a space.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With