2

有人可以帮忙吗我想将搜索模式(START& END)之间的所有行打印到不同的文件(new_file_name可以是提供的任何增量名称)

但是搜索模式在文件中重复,因此每次找到模式时,它都应该将行 b/w 转储到不同的文件中

该文件是这样的

START --- ./body1/b1
##########################

123body1
abcbody1

##########################
END --- ./body1/b1

START --- ./body2/b2
##########################

123body2
defbody2

##########################
END --- ./body2/b2
4

7 回答 7

1

要获取自动生成的增量文件名:

awk '
/^END/   { inBlock=0 }
inBlock  { print > outfile }
/^START/ { inBlock=1; outfile = "outfile" ++count }
' file

要使用输入中的文件名:

awk '
/^END/   { inBlock=0 }
inBlock  { print > outfile }
/^START/ {
    inBlock=1
    outdir = outfile = $NF
    sub(/\/[^\/]+$/,"",outdir)
    system("mkdir -p \"" outdir "\"")
}
' file

@JamesBond 下面的问题是我没有在 sub() 的字符列表中转义“/”,所以我现在更新了上面的答案。绝对没有理由需要对其进行转义,但显然 nawk 和 /usr/xpg4/bin/awk 都需要它:

$ cat file
the
quick/brown
dog

$ gawk '/[/]/' file
quick/brown

$ nawk '/[/]/' file
nawk: nonterminated character class [
 source line number 1
 context is
         >>> /[/ <<< ]/

$ /usr/xpg4/bin/awk '/[/]/' file
/usr/xpg4/bin/awk: /[/: [ ] imbalance or syntax error  Context is:
>>>     /[/     <<<

而且 gawk 也不在乎:

$ gawk --lint --posix '/[/]/' file
quick/brown

$ gawk --lint '/[/]/' file        
quick/brown

$ gawk --lint --posix '/[\/]/' file
quick/brown

$ gawk --lint '/[\/]/' file        
quick/brown

如果我转义反斜杠而不将其放入字符列表中,它们都可以正常工作:

$ /usr/xpg4/bin/awk '/\//' file    
quick/brown

$ nawk '/\//' file             
quick/brown

$ gawk '/\//' file
quick/brown

所以我想这对于未来的便携性来说是值得记住的!

于 2013-08-13T12:30:33.283 回答
1

这是我的awk解决方案:

# print_between_patterns.awk
/^START/ { filename = $NF ; next } # On START, use the last field as file name
/^END/ { next }                    # On END, skip
{ print > filename }               # For the rest of the lines, print to file

假设您的数据文件被称为data.txt,以下将执行您想要的操作:

awk -f print_between_patterns.awk data.txt

讨论

  • 脚本运行后,您将拥有./body1./body2等。
  • 如果您不想跳过 BEGIN 和 END 部分,请删除这些next命令。

更新

如果要按顺序控制输出文件名:

/^START/ { filename = sprintf("out%04d.txt", ++count) ; next }
/^END/ { next }
{ print > filename }
于 2013-08-13T05:16:57.670 回答
1

perl 解决方案,

perl -MFile::Basename -MFile::Path -ne '
  ($a) = /^START.+?(\S+)$/;
  $b = /^END/; 
  $a..$b or next; 
  if ($a){ mkpath(dirname $a); open STDOUT,">",$a; }
  $a||$b or print;
' file
于 2013-08-13T07:03:01.030 回答
0

这是在 Bash 中执行此操作的一种方法。

#!/bin/bash

[ -n "$BASH_VERSION" ] || {
    echo "You need Bash to run this script."
    exit 1
}

shopt -s extglob || {
    echo "Unable to enable extglob shell option."
    exit 1
}

IFS=$' \t\n' ## Use default.

while read KEY DASH FILENAME; do
    if [[ $KEY == START && $DASH == --- && -n $FILENAME ]]; then
        CURRENT_FILENAME=$FILENAME
        DIRNAME=${FILENAME%%+([^/])}
        if [[ -n $DIRNAME ]]; then
            mkdir -p "$DIRNAME" || {
                echo "Unable to create directory $DIRNAME."
                exit 1
            }
        fi
        exec 4>"$CURRENT_FILENAME" || {
            echo "Unable to open $CURRENT_FILENAME for output."
            exit 1
        }
        for (( ;; )); do
            IFS= read -r LINE || {
                echo "End of file reached finding END block of $CURRENT_FILENAME."
                exec 4>&-
                exit 1
            }
            read -r KEY DASH FILENAME <<< "$LINE"
            if [[ $KEY == END && $DASH == --- && $FILENAME == "$CURRENT_FILENAME" ]]; then
                break
            else
                echo "$LINE" >&4
            fi
        done
        exec 4>&-
    fi
done

确保将脚本保存为 UNIX 文件格式,然后以bash script.sh < file.

于 2013-08-13T06:16:25.253 回答
0

This might work for you:

csplit -z file '/^START/' '{*}'

Files will be named xx00 xx01 xx..

于 2013-08-13T07:24:45.837 回答
0

我想你需要看看这个

perl -lne 'print if((/START/../END/) and ($_!~/START/ and $_!~/END/))' your_file

测试如下:

> cat temp
START --- ./body1
##########################

123body1
abcbody1

##########################
END --- ./body1

START --- ./body2
##########################

123body2
defbody2

##########################
END --- ./body2
> perl -lne 'print if((/START/../END/) and ($_!~/START/ and $_!~/END/))' temp
##########################

123body1
abcbody1

##########################
##########################

123body2
defbody2

##########################
> 
于 2013-08-13T07:06:43.523 回答
0

使用 awk:

awk 'sub(/^START/, ""){out=sprintf("out%d", c++); p=1}
     sub(/^END/, ""){print > out; p=0} p{print > out}' file

START这将在名为等END的单独文件out1中查找并存储每个匹配项out2

于 2013-08-13T05:10:06.613 回答