Home > other >  Make tr replace only exact characters given in arguments
Make tr replace only exact characters given in arguments

Time:09-12

I'm trying to convert filenames to remove unacceptable characters, but tr doesn't always treat its input arguments exactly as they're given.

For example:

$ echo "(hello) - {world}" | tr '()-{}' '_'
_______ _ _______

...whereas I only intended to replace (, ), -, { and }, all the characters between ) and { in ASCII collation order were replaced as well -- so every letter in the input also became a _!

Is there a way to make tr replace only the exact characters given in its argument?

CodePudding user response:

tr's syntax is surprisingly complicated. It supports ranges, character classes, collation-based equivalence matching, etc.

To avoid surprises (when a string matches any of that syntax unexpectedly), we can convert our literal characters to a string of \### octal specifiers of those characters' ordinals:

trExpressionFor() {
  printf %s "$1" | od -v -A n -b | tr ' ' '\\'
}

trL() { # name short for "tr-literal"
  tr "$(trExpressionFor "$1")" "$(trExpressionFor "$2")"
}

...used as:

$ trExpressionFor '()-{}'
\050\051\055\173\175
$ echo "(hello) - {world}" | trL '()-{}' '_'
_hello_ _ _world_
  • Related