【发布时间】:2016-08-05 15:05:53
【问题描述】:
使用 Mac OS X 命令行,我想在当前目录及其许多子目录中的 大量 文件中执行简单的查找和替换。
我需要执行许多替换,因此我希望脚本尽可能高效。
无论我尝试什么似乎都会导致一些随机错误,所以我终于寻求帮助。
所以鉴于我有两个变量:
FIND=oldText
REPLACE=newText
这是我迄今为止尝试过的:
sed -i '' "s/${FIND}/${REPLACE}/g" *
> sed: Build: in-place edditing only works for regular expressions
显然这是试图对目录路径本身进行 sed,所以我随后尝试(排除目录被 sed'ed)
find * -type f -print | xargs sed -i '' "s/${FIND}/${REPLACE}/g"
> xargs: sed: Argument list too long
所以因为我有这么大的文件列表来操作 xargs 无法处理它。显然 -exec 更适合大型列表..
find * -type f -print -exec sed -i '' "s/${FIND}/${REPLACE}/g" {} \;
现在这确实有效,但是 sed 决定它必须纠正所有文件中丢失的 eof/换行符,尽管文件中没有替换。不幸的是,有成千上万个这种性质的文件,我不能为当前的工作进行如此大规模的更改。 (请不要宣扬我应该如何更正文件,这不是我要问的问题)。
因此,为了解决这个问题,我尝试首先提取确实包含我的 ${FIND} 术语的文件列表,然后只对这些文件执行 sed...
grep -r -l -e "${FIND}" "." | sed -i '' "s/${FIND}/${REPLACE}/g"
> sed: -i may not be used with stdin
-
grep -r -l -e "${FIND}" "." | -exec sed -i '' "s/${FIND}/${REPLACE}/g" {} \;
> ./file1.txt: line 10: -exec: command not found
-
$( grep -r -l -e "${FIND}" "." ) -exec sed -i '' "s/${FIND}/${REPLACE}/g" {} \;
> ./file1.txt: line 10: -exec: command not found
-
FILEPATHS_CONTAINING_FIND=$( grep -r -l -e "${FIND}" "." )
sed -i '' "s/${FIND}/${REPLACE}/g" "${FILEPATHS_CONTAINING_FIND}"
> sed: ./File1.txt
./File2.txt
./File3.txt: No such file or directory
我认为这里将变量 ${FILEPATHS_CONTAINING_FIND} 视为单个长文件路径。如果我删除双引号 "" 它不会处理带有空格的路径,所以这也不是一个选项。 现在回到尝试 xargs ,因为过滤后的文件列表更短了...
$( grep -r -l -e "${FIND}" "." ) | xargs sed -i '' "s/${FIND}/${REPLACE}/g"
> ./Script.sh: line 10: ./File1.txt: Permission denied
在不同的地方尝试 sudo 没有区别。
无论如何,我已经使用了这个 for 循环,但我真的更喜欢更简洁和高效的东西。
IFS=$'\n' # Ensure spaces don't mess up the for loop
for FILEPATH_CONTAINING_FIND in $(grep -r -l -e "${FIND}" "."); do
sed -i '' "s/${FIND}/${REPLACE}/g" "${FILEPATH_CONTAINING_FIND}"
done
谁能帮我解决上面遇到的问题?
【问题讨论】:
-
为什么在脚本还没有工作的情况下使用
-i ''覆盖文件?只有当您非常有信心整个事情会正常工作时,才应该在没有备份的情况下覆盖文件。好吧,没关系;它们是你的文件——你可以随心所欲。但是理智要求你不要(通常)四处覆盖文件,直到你确定你会做对。 -
如果您要使用
-exec,请使用{} +而不是{} \;,因为它使find的行为类似于xargs并使用多个文件名作为参数运行。错误消息xargs: sed: Argument list too long很奇怪。你的${FIND}和${REPLACE}字符串到底有多长? -
“所以试图克服这个问题”之后的 4 个命令序列很奇怪。他们应该失败。您是否有要处理的带有空格的文件名?如果不是,那么
grep -r -l … | xargs sed …应该处理包含匹配项的文件。如果名称中包含可移植文件名字符集之外的空格或其他字符,请说明。它使你的工作更难。如果你的文件名包含换行符,那就更难了;这将是重要的信息。 -
@JonathanLeffler,我使用 git,所以所有文件都被备份,我可以简单地在两次尝试之间重置我的工作副本。感谢您的关心。
-
${FIND} 和 ${REPLACE} 在这种情况下特别短,一般是个位数,没有字符。