用 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。
所以我删除了文件名中的特殊字符并替换为空格。除了其中包含单个反斜杠的文件之外,我都在工作。 请注意,这些文件是在 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。