使用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
任何人都可以帮我解决上面遇到的问题吗?
答案 0 :(得分:1)
您可以像这样使用find + grep + sed
:
# cd to parent dir
while IFS= read -d '' -r file; do
grep -q "$FIND" "$file" &&
sed -i '' "s/${FIND}/${REPLACE}/g" "$file"
done < <(find . -type f -print0)
print0
我们从find
命令read -d ''
我们对空字节进行read
分隔grep -q
我们确保在运行$FIND
sed
$FIND
只是一个普通字符串,那么您可以考虑使用grep -F
编辑:您可以使用for
循环和while
改进grep -r --null
循环:
while IFS= read -d '' -r file; do
sed -i '' "s/${FIND}/${REPLACE}/g" "$file"
done < <(grep -lR --null "$FIND" .)