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_