2016-11-08 166 views
3

所以我删除文件名中的特殊字符并用空格替换。除了其中包含单反斜杠的文件外,我已经开始工作了。 注意这些文件在Finder中创建了OS X删除反斜杠与tr

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

这将导致NEW_NAME被“测试hisolder” 如何我只是删除了反斜杠,而不是前面的字符?

+1

根据你如何定义_special characters_,你可以使用'tr -d'[:punct:]'' –

回答

3

这将导致NEW_NAME被 “测试hisolder”

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

也许你有一个别名像alias echo='echo -e',或者可能的echo在外壳的版本执行解释反斜杠:

POSIX不需要任何选项的支持,并且说的 行为如果任何STRING包含 反斜杠或第一个参数为“-n”,则'echo'是实现定义的。如果便携式程序需要省略尾部换行符或输出控制字符或反斜杠,则可以使用'printf'命令使用 。

(从信息页)

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

例如this discussion有一个很好的解释。

无需printf

正如@ mklement0建议,您可以通过Bash here string的手段避免管道:

tr '<>:\\#%|?*' ' ' <<<"$old_name" 
2

使用bash,你可以使用参数扩展:

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

有关详细信息,请参阅猛砸手册上shell parameter expansion

-1

我认为你的测试用例丢失了\的正确转义,所以你并不真正测试包含在字符串中的反斜杠的情况。

这为我工作:

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

在Bash(这是如何标记问题)中使用默认选项,使用它的'echo'内建,这将保留_both_反斜杠,并且结果字符串在单词之间会有_2_空格。 (相反,OP的代码应该按原样工作。)除此之外,“$ old_name”应该用双引号。你的转义只能在打开(隐式或显式)选项'xpg_echo'的情况下才能起作用,但更好的解决方案是使用'printf'或一个here-string。 – mklement0

2

Ruslan's excellent answer解释了为什么你的命令可能不会为你工作,并提供强大的便携式解决方案。

TL;博士

  • 你可能有sh而非bash(即使在MacOS sh这是Bash的化身)跑了你的代码,或者你有shell选项xpg_echo明确地打开。
  • 为了便于携带,请使用printf而不是echo

在bash,使用默认选项,并使用echo内置,命令将正常运行,是(除了你应该用双引号$old_name稳健性),因为echo(默认设置)在其操作数中扩展转义序列,如\t

然而,bash的echo可以进行扩大控制字符转义序列:

  • 明确,通过执行shopt -s xpg_echo
  • 含蓄,如果你运行bash作为sh或与--posix选项( ,以及其他选项和行为变化,激活xpg_echo

因此,您的s例如,ymptom可能是由脚本以脚本行#!/bin/sh运行代码引起的。

但是,如果你的目标sh,即,如果你正在写一个便携式脚本,然后echo应该完全避免的原因恰恰是它的行为跨越炮弹和平台的不同 - 见鲁斯兰的printf解决方案。


顺便说一句:或许是一个更强大的方式来你tr命令是白名单方法:仅指出明确允许在结果中的字符,并排除其他与-C选项:

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

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

+0

感谢您的详细解释 – rndy