如何将文件的某些部分转移到另一个文件?

如何将文件的某些部分转移到另一个文件?

我有一个 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来获取特定行之间的模式,然后过滤掉startstop标志:

$ 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

当然有其他方法,例如sedperl。至于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

相关内容