用 tr 去除反斜杠

removing backslash with tr

所以我删除了文件名中的特殊字符并替换为空格。除了其中包含单个反斜杠的文件之外,我都在工作。 请注意,这些文件是在 OS X

的 Finder 中创建的
old_name="testing\this\folder"
new_name=$(echo $old_name | tr '<>:\#%|?*' ' ');

这导致 new_name 成为 "testing hisolder" 我怎样才能只删除反斜杠而不是前面的字符?

配合Bash,可以使用参数展开:

$ old_name="testing\this\folder"
$ new_name=${old_name//[<>:\#%|?*]/ }
$ echo $new_name
testing this folder

有关更多信息,请参阅 shell parameter expansion 上的 Bash 手册。

我认为您的测试用例缺少 \ 的正确转义,因此您并没有真正测试字符串中包含反斜杠的情况。

这对我有用:

old_name='testing\this\folder'
new_name=$(echo $old_name | tr '<>:\#%|?*' ' ');
echo $new_name
# testing this folder

This results in new_name being "testing hisolder"

这个字符串看起来像echo -e "testing\this\folder"的结果,因为\t\f实际上被制表符和换页控制字符替换了.

也许你有一个像 alias echo='echo -e' 这样的别名,或者你的 shell 版本中 echo 的实现解释了反斜杠转义:

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.

(来自信息页)

所以你应该在新软件中使用printf而不是echo。特别是,echo $old_name 应替换为 printf %s "$old_name"

例如this discussion中有很好的解释。

不需要printf

正如@mklement0 所建议的那样,您可以通过 Bash here string:

来避开管道
tr '<>:\#%|?*' ' ' <<<"$old_name"

解释了为什么您的命令可能不适合您,并提供了一个强大的、可移植的解决方案。

tl;dr:

  • 您可能 运行 您的代码使用 sh 而不是 bash(即使在 macOS 上 sh 是伪装的 Bash),或者您有shell 选项 xpg_echo 明确开启。
  • 为了便携性,使用 printf 而不是 echo

在 Bash 中,使用默认选项并使用 echo 内置命令,您的命令应该按原样工作(除了您应该双引号 $old_name 以确保稳健性),因为 echo 默认情况下 不会 扩展转义序列,例如在其 ope运行ds.

中的 \t

但是,Bash 的 echo 可以 扩展控制字符转义序列:

  • 明确地,通过执行shopt -s xpg_echo
  • 隐含地,如果您 运行 Bash 作为 sh 或使用 --posix 选项(除其他选项和行为更改外,激活 xpg_echo )

因此,例如,您的症状可能是由于 运行从带有 shebang 行 #!/bin/sh 的脚本中编译代码引起的。

但是,如果您的目标是 sh,即,如果您正在编写 可移植 脚本,则应完全避免 echo它的行为在 shell 和平台上不同的原因 - 请参阅 Ruslan 的 printf 解决方案。


顺便说一句:也许 tr 命令更可靠的方法是 白名单 方法:仅说明结果中明确允许的字符,并且使用 -C 选项排除其他:

old_name='testing\this\folder'
new_name=$(printf '%s' "$old_name" | tr -C '[:alnum:]_-' ' ')

这样,任何不是字母、数字、_- 的字符都将替换为 space。