在Mac OS X上使用Sed的多个问题

时间:2016-08-05 15:05:54

标签: bash macos shell sed

使用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

任何人都可以帮我解决上面遇到的问题吗?

1 个答案:

答案 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" .)