所以我从文件名中删除特殊字符并用空格替换。我所有的工作除了文件与单反斜杠包含在其中。注意,这些文件是在OS X的查找器中创建的
old_name="testingthisfolder"
new_name=$(echo $old_name | tr '<>:\#%|?*' ' ');
这会导致new_name为"testing hisolder"我怎么能只删除反斜杠而不删除前一个字符?
这导致new_name为"testing hisolder"
这个字符串看起来像echo -e "testingthisfolder"
的结果,因为 t
和f
实际上被替换为制表和表单输入控制字符。
也许您有一个别名,如alias echo='echo -e'
,或者echo
的实现在您的shell版本中解释反斜杠转义:
POSIX不需要支持任何选项,并且表示' echo '的行为是实现定义的,如果任何STRING包含反斜杠或者第一个参数是' -n '。便携式程序可以使用如果他们需要省略尾随换行符或输出,则使用' printf '命令控制字符或反斜杠
(来自信息页)
所以在新软件中应该使用printf
而不是echo
。特别是,echo $old_name
应该替换为printf %s "$old_name"
。
例如,在这个讨论中有一个很好的解释。
不需要printf
正如@mklement0所建议的,您可以通过Bash here字符串来避免管道:
tr '<>:\#%|?*' ' ' <<<"$old_name"
Ruslan出色的回答解释了为什么您的命令可能不适合您,并提供了一个健壮的,可移植的解决方案。
tl;博士:
- 您可能使用
sh
而不是bash
运行代码(即使在macOS上sh
是伪装的Bash),或者您显式打开了shell选项xpg_echo
。 - 使用
printf
代替echo
来实现可移植性。
在Bash中,使用默认选项并使用内置的echo
,您的命令应该按原样工作(除了应该为健壮性对$old_name
双引号),因为默认情况下echo
不会在其操作数中展开转义序列,例如t
。但是,Bash的echo
可以用来扩展控制字符转义序列:
- 通过执行
- 隐式地,如果您以
sh
或--posix
选项运行Bash(在其他选项和行为更改中,该选项激活xpg_echo
)
shopt -s xpg_echo
显式地因此,您的症状可能是由从脚本中运行代码引起的,例如,在脚本中运行#!/bin/sh
行。
然而,如果你的目标是sh
,也就是说,如果你正在编写一个可移植的脚本,那么echo
应该完全避免,因为它的行为在shell和平台上是不同的——参见Ruslan的printf
解决方案。
作为题外话:也许
tr
命令更健壮的方法是白名单方法:仅声明结果中显式允许的字符,并使用-C
选项排除其他字符:
old_name='testingthisfolder'
new_name=$(printf '%s' "$old_name" | tr -C '[:alnum:]_-' ' ')
这样,任何不是字母、数字、_
或-
的字符都将被替换为空格。
对于Bash,您可以使用参数展开:
$ old_name="testingthisfolder"
$ new_name=${old_name//[<>:\#%|?*]/ }
$ echo $new_name
testing this folder
更多信息,请参考Bash手册中的shell参数扩展。
我认为您的测试用例缺少的适当转义,因此您并没有真正测试字符串中包含的反斜杠的情况。
这个为我工作:
old_name='testing\this\folder'
new_name=$(echo $old_name | tr '<>:\#%|?*' ' ');
echo $new_name
# testing this folder