我有很多文字文件,我希望在其中找到“' CASE'并用相关的文件名替换它。 我试过了
find . -type f | while read file
do
awk '{gsub(/CASE/,print "FILENAME",$0)}' $file >$file.$$
mv $file.$$ >$file
done
但是我收到了以下错误
awk:源代码行1上下文的语法错误是>>> {gsub(/ CASE /,print<<<" CASE",$ 0)}
awk:源代码行1的非法声明
我也试过
for i in $(ls *);
do
awk '{gsub(/CASE/,${i},$0)}' ${i} > file.txt;
done
获得空输出
awk:源代码行1上下文的语法错误是>>> {gsub(/ CASE /,$ {<<<
awk:源代码行1的非法声明
答案 0 :(得分:2)
为什么awk
? sed
就是你想要的:
while read -r file; do
sed -i "s/CASE/${file##*/}/g" "$file"
done < <( find . -type f )
或
while read -r file; do
sed -i.bak "s/CASE/${file##*/}/g" "$file"
done < <( find . -type f )
创建原始备份。
答案 1 :(得分:2)
您没有发布任何样本输入和预期输出,所以这是猜测,但也许这就是您想要的:
find . -type f |
while IFS= read -r file
do
awk '{gsub(/CASE/,FILENAME)} 1' "$file" > "${file}.$$" &&
mv "${file}.$$" "$file"
done
我对shell代码所做的每一项更改都很重要,所以如果你不明白为什么我改变了它的任何部分,请提出问题。
btw如果在进行更改后仍然收到错误消息:
awk: syntax error at source line 1
awk: illegal statement at source line 1
然后你使用旧的,破坏的awk(Solaris上的/ usr / bin / awk)。永远不要使用那个awk。在Solaris上使用/ usr / xpg4 / bin / awk(如果必须,则使用nawk)。
注意事项:如果您的文件名包含换行符或&符号(&
)或转义数字(例如\1
),则上述操作将失败。有关详细信息,请参阅Is it possible to escape regex metacharacters reliably with sed。如果有任何问题,请发布一些有代表性的样本输入和预期输出。
答案 2 :(得分:1)
print
是错误。
gsub
的第二个参数是替换字符串而不是命令。
您只想FILENAME
。 (注意,"FILENAME"
不是文字字符串。FILENAME
变量。)
find . -type f -print0 | while IFS= read -d '' file
do
awk '{gsub(/CASE/,FILENAME,$0)} 7' "$file" >"$file.$$"
mv "$file.$$" "$file"
done
请注意,我引用了所有变量并修复了find | read
管道,以便在名称中包含奇数字符的文件中正常工作(有关详细信息,请参阅Bash FAQ 001)。我还修复了>
命令中的错误mv
。
请参阅this question上的答案,了解如何正确转义原始文件名,以便在gsub
的替换部分中安全使用。
另请注意,最近(我认为4.1+)版本的awk具有-i inplace
参数。
要修复第二个脚本,您需要添加从第一个脚本中删除的引号。
for i in *; do awk '{gsub(/CASE/,"'"${i}"'",$0)}' "${i}" > file.txt; done
请注意,我摆脱了比使用ls
更糟糕的情况(更糟糕的是因为它主动破坏了名称中包含空格或shell元字符的文件(有关详情,请参阅Parsing ls)
虽然这个命令对于其中包含各种字符的文件名来说有些难看且不安全,但是可以更好地编写如下:
for i in *; do awk -v fname="$i" '{gsub(/CASE/,fname,$0)}' "${i}" > file.txt; done
因为这将适用于带双引号/ etc的文件名。在他们的名字正确,而直接变量扩展版本不会。
据说纠正的第一个脚本是正确的答案。