Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

removing backslash with tr

Tags:

bash

macos

tr

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?

like image 231
rndy Avatar asked Nov 08 '16 14:11

rndy


2 Answers

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"
like image 141
Ruslan Osmanov Avatar answered Nov 03 '22 01:11

Ruslan Osmanov


Ruslan's excellent answer explains why your command may not be working for you and offers a robust, portable solution.

tl;dr:

  • You probably ran your code with sh rather than bash (even though on macOS sh is Bash in disguise), or you had shell option xpg_echo explicitly turned on.
  • Use 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:

  • explicitly, by executing shopt -s xpg_echo
  • implicitly, if you run Bash as 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.

like image 28
mklement0 Avatar answered Nov 03 '22 00:11

mklement0