嘿,我试着写一个小小的bash脚本。这应该复制一个目录和其中的所有文件。然后它应该在这个复制的目录中搜索每个文件和目录中的一个字符串(例如@ForTestingOnly),然后保存行号。然后它应该继续计算每个{和}一旦数字等于它应该保存线号。 =>它应该删除这两个数字之间的所有行。 我正在尝试创建一个搜索所有这些注释的脚本,然后删除直接在此ano之后的方法。 求救......
到目前为止,我有:echo "please enter dir"
read dir
newdir="$dir""_final"
cp -r $dir $newdir
cd $newdir
grep -lr -E '@ForTestingOnly' * | xargs sed -i 's/@ForTestingOnly//g'
现在用grep我可以搜索并替换@ForTestingOnly anot。但我想删除这个和以下方法...
答案 0 :(得分:2)
试一试。然而,正如 David Gelhar 所警告的那样,它在评论和文字中没有注意到。它只查找并删除第一次出现的“@ForTestingOnly”块(假设只有一个块)。
#!/bin/bash
find . -maxdepth 1 | while read -r file
do
open=0 close=0
# start=$(sed -n '/@ForTestingOnly/{=;q}' "$file")
while read -r line
do
case $line in
*{*) (( open++ )) ;;
*}*) (( close++ ));;
'') : ;; # skip blank lines
*) # these lines contain the line number that the sed "=" command printed
if (( open == close ))
then
break
fi
;;
esac
# split braces onto separate lines dropping all other chars
# print the line number once per line that contains either { or }
# done < <(sed -n "$start,$ { /[{}]/ s/\([{}]\)/\1\n/g;ta;b;:a;p;=}" "$file")
done < <(sed -n "/@ForTestingOnly/,$ { /[{}]/ s/\([{}]\)/\1\n/g;ta;b;:a;p;=}" "$file")
end=$line
# sed -i "${start},${end}d" "$file"
sed -i "/@ForTestingOnly/,${end}d" "$file"
done
修改:删除了对sed
的一次通话(通过注释并替换了几行)。
编辑2:
以下是主sed
行的细分:
sed -n "/@ForTestingOnly/,$ { /[{}]/ s/\([{}]\)/\1\n/g;ta;b;:a;p;=}" "$file"
-n
- 仅在明确请求时打印行/@ForTestingOnly/,$
- 从包含“@ForTestingOnly”的行到文件末尾s/ ... / ... /g
执行全局(每行)替换\( ... \)
- 捕获[{}]
- 列表中出现的字符位于方括号\1\n
- 替换捕获的内容加上换行符ta
- 如果进行了替换,则分支到标签“a”b
- 分支(没有标签意味着“到最后并再次为下一行开始每行循环) - 这个分支充当ta
的”其他“,我可以已使用T
代替ta;b;:a
,但某些版本的sed
不支持T
:a
- 标签“a”p
- 打印行(实际上,打印模式缓冲区,现在可能包含多行,每行包含“{”或“}”)=
- 打印输入文件的当前行号第二个sed
命令只是说删除从具有目标字符串并以while
循环找到的行结束的行开始的行。
我评论出的顶部的sed
命令说找到目标字符串并打印它所在的行号并退出。该行不是必需的,因为主sed
命令负责在正确的位置开始。
内部while
循环查看主sed
命令的输出,并为每个大括号递增计数器。当计数匹配时,它就会停止。
外部while
循环遍历当前目录中的所有文件。
答案 1 :(得分:0)
我修复了旧版本中的错误。新版本有两个脚本:awk脚本和bash驱动程序。
司机是:
#!/bin/bash
AWK_SCRIPT=ann.awk
for i in $(find . -type f -print); do
while [ 1 ]; do
cmd=$(awk -f $AWK_SCRIPT $i)
if [ -z "$cmd" ]; then
break
else
eval $cmd
fi
done
done
新的awk脚本是:
BEGIN {
# line number where we will start deleting
start = 0;
}
{
# check current line for the annotation
# we're looking for
if($0 ~ /@ForTestingOnly/) {
start = NR;
found_first_open_brace = 0;
num_open = 0;
num_close = 0;
}
if(start != 0) {
if(num_open == num_close && found_first_open_brace == 1) {
print "sed -i \'\' -e '" start "," NR " d' " ARGV[1];
start = 0;
exit;
}
for(i = 1; i <= length($0); i++) {
c = substr($0, i, 1);
if(c == "{") {
found_first_open_brace = 1;
num_open++;
}
if(c == "}") {
num_close++;
}
}
}
}
在驱动程序中设置awk脚本的路径,然后在根目录中运行驱动程序。