我有一个 FILE1
NAMES START
Hi, How are you?
Good to see you
start
Aaron
Kyle
Robert
stop
Official use only
Stamps here
start
Riley
Gayle
stop
Bicycles here
United Pawns
start
Alex
Ford
Sergio
stop
NAMES STOP
这就是我想要做的事情:
如果存在“NAMES START”字符串,则将每个“start”和“stop”的内容传输到新的FILE2,而在新的FILE2中保留start和stop本身。
因此 FILE2 应如下所示:
Aaron
Kyle
Robert
Riley
Gayle
Alex
Ford
Sergio
请帮助!
答案1
获取命名文本块之间的内容
让我们解决获取块内的内容的问题start..stop
,因为这是主要任务。
grep
是线路匹配工具,因此跨多条线路匹配很困难,grep
通常不用于此类任务,虽然这并非不可能。但是,在这种情况下最好的方法是使用awk
来获取特定行之间的模式,然后过滤掉start
和stop
标志:
$ awk '/start/,/stop/' input.txt | grep -v 'start\|stop'
Aaron
Kyle
Robert
Riley
Gayle
Alex
Ford
Sergio
如果我们想摆脱管道,我们可以这样做:
# {print} is actually unnecessary, as default for awk is to print if
# expression evaluates to true, so it's enough to have
# awk '/start/{flag=1;next};/stop/{flag=0};flag' input.txt
$ awk '/start/{flag=1;next};/stop/{flag=0};flag == 1 {print}' input.txt
Aaron
Kyle
Robert
Riley
Gayle
Alex
Ford
Sergio
当然有其他方法,例如sed
或perl
。至于grep
,通常建议使用grep -Pzo
标志,但可能是由于 多次出现而start..block
无法正常工作(仅返回一个匹配项):
$ grep -zPo --color 'start\n(.*\n.*)\nstop' input.txt
start
Riley
Gayle
stop
为了简单起见(尽管可以说awk
示例是最简单的)并为了避免处理正则表达式模式,我们也可以采用基本脚本:
#!/bin/bash
printline=0
while IFS= read -r line; do
# set flag for printing or not printing
case $line in
"start") printline=1; continue;;
"stop") printline=0; continue;;
esac
# check the flag
if [ "$printline" -eq 1 ]; then
printf "%s\n" "$line"
fi
# first positional parameter is the file we read
done < "$1"
脚本的工作原理如下:
$ chmod +x readblocks.sh
$ ./readblocks.sh input.txt
Aaron
Kyle
Robert
Riley
Gayle
Alex
Ford
Sergio
检查 NAMES START 并传输
如果存在“NAMES START”字符串,则将每个“start”和“stop”的内容传输到新的FILE2,而在新的FILE2中保留start和stop本身。
嗯,那只是grep 'NAMES START' input.txt
。所以我们可以通过以下方式检查
if grep -q 'NAMES START' input.txt; then
# whatever method you like goes here
fi
看看您的示例,NAMES START
这是文件的第一行。所以我们也可以检查这一点 - 在读取文件时检查第一行,而不是在if
上面建议的语句中打开文件。
将内容传输到 FILE2 - 这只是添加> FILE2.txt
到您使用的原始命令或脚本。
有了这些建议,awk
命令就变成:
$ awk 'NR==1 && $0 != "NAMES START"{exit};/start/{flag=1;next};/stop/{flag=0};flag' input.txt > FILE2.txt
脚本如下:
#!/bin/bash
printline=0
linecounter=0
while IFS= read -r line; do
linecounter=$((linecounter+1))
case "$line" in
"NAMES START") continue;;
*) exit 1;
esac
# set flag for printing or not printing
case $line in
"start") printline=1; continue;;
"stop") printline=0; continue;;
esac
# check the flag
if [ "$printline" -eq 1 ]; then
printf "%s\n" "$line"
fi
# first positional parameter is the file we read
done < "$1" > FILE2.txt