笔记: 我知道这个问题:如何 grep 反向匹配并排除“之前”和“之后”行。我的不是前面引用的重复项,该问题的答案也会删除该模式,而在这个问题中,模式本身必须保留。
我试图删除模式后面的 n 行和模式之前的 m 行(不删除模式)。例如,如果文件是:
1
2
3
4
5
6
7
8
9
如果 Pattern = 5,n = 2,m = 3。则:
1
5
8
9
您能建议如何做到这一点吗?
奖金:如果我们可以在同一代码中设置 m 或 n = 0,那就太好了。例如。如果我们设置 m=0 和 n=1,在上面的例子中,我们应该得到:
1
2
3
4
5
7
8
9
答案1
为了回答您的一般情况,我们会ed
根据给定的输入类型提前构建适当的代码。
re=5 n=2 m=3
code=$(
prev="/$re/-$m,/$re/-1d"
next="/$re/+1,/$re/+${n}d"
case "$m/$n" in
0/0) set -- ;;
0/?*) set -- "$next" "w" ;;
?*/0) set -- "$prev" "w" ;;
*) set -- "$prev" "$next" "w" ;;
esac
printf '%s\n' ${1+"$@"} "q"
)
ed -s filename - <<eof
$code
eof
一种方法可能是:这使用ed
编辑器执行相对寻址,因为这就是您的问题的中心。
n=3 m=2 re=5
ed -s filename - <<eof
/$re/-$m,/$re/-1d
.+1,.+${n}d
wq
eof
解释:
1. Line 3 after var substitution becomes
/5/-2,/5/-1
What it does is, sitting on line which satisfies the regex /5/, it looks 2 lines behind and stops looking 1 line before the /5/ line or the current line and deletes that bunch. Remember the current line is not deleted.
2. Line 4, after var sub becomes
.+1,.+3d
. is the nickname for the current line, which in our case is /5/
So, starting fron one line after the current upto 3 lines after the current, delete them all. Note the current line is still untouched.
3. Line 5 is wq which means save the modified file back onto itself and quit.
For more on info google the manual for gnu ed editor.
答案2
假设您有一个文件 - numbers.list
:
1
2
3
4
5
6
7
8
9
这是一个应该可以完成您所追求的任务的脚本:
#!/bin/bash
if [ -z "$1" ]; then
echo >&2 "error: no file specified"
exit 1
fi
if [ ! -f "$1" ]; then
echo >&2 "error: $1 is not a file"
exit 1
fi
if [ -z "$2" ]; then
echo >&2 "error: no pattern specified"
exit 1
fi
grep "$2" "$1" >/dev/null 2>&1
if [ ! 0 -eq "$?" ]; then
echo >&2 "error: pattern $2 not found in $1"
exit 1
fi
MATCH_FILE="$1"
MATCH_PATTERN="$2"
MATCH_DELETE_AFTER=0
MATCH_DELETE_BEFORE=0
if [ ! -z "$3" ]; then
MATCH_DELETE_AFTER="$3"
fi
if [ ! -z "$4" ]; then
MATCH_DELETE_BEFORE="$4"
fi
MATCH_FILE_LINE="$( grep -n "$2" "$1" | cut -d: -f1 )"
#
# print matching `head` minus MATCH_DELETE_BEFORE lines
cat "$1" \
| head -n "$( expr "$MATCH_FILE_LINE" - "$MATCH_DELETE_BEFORE" - 1 )"
#
# print matching line
cat "$1" \
| head -n "$MATCH_FILE_LINE" \
| tail -n 1
#
# print matching `tail` minus MATCH_DELETE_AFTER lines
cat "$1" \
| tail -n "$( expr "$( wc -l "$1" | cut -d' ' -f1 )" - "$MATCH_FILE_LINE" - "$MATCH_DELETE_AFTER" )"
用法示例: ./matching.sh numbers.list 5 2 3
笔记:expr
如果计算负值,则此解决方案将无法按预期工作- 如果您想实施检查以避免这种行为,则由您决定。