2017-10-13 124 views
0

文件我有这将有以下模式拆分基于图案

HDR1|20160101|1234| 
N1|ABC| 
XXX|21431415|3522352352|ITEM| 
FORE|20140508|20140214| 
SD|0|0039 - data|data|data|data| 
SD|0|0211 - data|data|data|data| 
SD|0|0039 - data|data|data|data| 
SD|0|0211 - data|data|data|data| 
FORE|20140508|20140214| 
SD|0|0039 - data|data|data|data| 
SD|0|0039 - data|data|data|data| 
SD|0|0211 - data|data|data|data| 

我想分裂基于尺寸的文件,但还需要采取以下护理文件。

前3行是标题,我需要将其包含在我创建的每个分割文件中。 以FORE开头的行与SD之后的行有关系,所以我必须将它们放在一起。

输出应如下所示。

分割文件1:

HDR1|20160101|1234| 
N1|ABC| 
XXX|21431415|3522352352|ITEM| 
FORE|20140508|20140214| 
SD|0|0039 - data|data|data|data| 
SD|0|0211 - data|data|data|data| 
SD|0|0039 - data|data|data|data| 
SD|0|0211 - data|data|data|data| 

分割文件2:

HDR1|20160101|1234| 
N1|ABC| 
XXX|21431415|3522352352|ITEM| 
FORE|20140508|20140214| 
SD|0|0039 - data|data|data|data| 
SD|0|0039 - data|data|data|data| 
SD|0|0211 - data|data|data|data| 

我建立了一个伪代码,它看起来像below.There可多套这样的船头和SD我”的已经保持在一起为一组,所以我已经把一个循环

create $file 
create $line_num=5 
create $file_size 
create $top_size=20mb 
read the first 4 lines of the original file and copy it in a temphdr file 
    Loop until last $line_num is encountered 
     read the header details and Append the header from the temphdr to the $file 
     for each $record starting the head -$line_num (5,6,7...etc) that contains FORE| in the first part 
      if the $file size is < $top_size 
       append the $record in the $file 

       increment $line_num 
       For each $record in head -$line_num that contains SD| in the first part 
        append the $record in the $file 
        increment $line_num 
      else 
       create a $file=$file+1 
      fi 
     end loop 
    end loop  

可能有人让我知道是否有任何其他影响一种使用awk和sed等的方式来实现这一点,而不是上面提到的高级逻辑。

+0

我注意到你最近的编辑 - 你有理由相信我的答案*不*已经做你要求的东西(重新:分裂只在一个FORE,保持作为一套与以下SDS)? –

+0

嘿查尔斯。对于那个很抱歉。我起初没有注意到它,所以我继续编辑我的问题,认为我可能没有详细阐述,但是后来立即注意到你已经考虑了我的观点。 :)。我为此感谢你.. – user3055262

+0

NP。唯一需要解释的问题是你是否想要在* FORE(如@ anubhava的答案)中分割,或者在20mb边界之后的第一个FORE中分割(就像我的答案一样)。 –

回答

1

几乎没有这么复杂的要求。这可以在完全没有外部命令的纯shell中实现(没有head,awk等)。

#!/usr/bin/env ksh 

max_size=$((20 * 1024 * 1024)) 

# Read our three fixed header lines 
headers='' 
read -r line; headers+="$line"$'\n' 
read -r line; headers+="$line"$'\n' 
read -r line; headers+="$line"$'\n' 

splitNum=1            # variable to track file number 
splitFileName=$(printf 'split.%04d' "$splitNum")  # generate first filename 
exec >"$splitFileName"         # and redirect stdout to that file 

printf '%s' "${headers}"        # print our headers... 
cur_size=$((${#headers}))       # and set cur_size to their length 

while IFS= read -r line; do       # For each line: 
    # check for and manage rotation 
    if [[ $line = "FORE|"* ]]; then      # If it's a FORE... 
    if ((cur_size > max_size)); then     # ...and over size: start a new file 
     ((++splitNum))         # increment the split number 
     splitFileName=$(printf 'split.%04d' "$splitNum") # generate a new filename 
     exec >"$splitFileName"       # redirect stdout to that file 
     printf '%s' "${headers}"       # print headers to stdout 
     cur_size=$((${#headers}))      # reset size to size of headers 
    fi 
    fi 
    # whether or not we had to do any of that: 
    printf '%s\n' "$line"        # print the line we just read 
    cur_size=$((cur_size + ${#line} + 1))    # and increment cur_size 
done 

请注意,如果你是这个移植到bash中,你可能想改变splitFileName=$(printf 'split.%04d' "$splitNum")printf -v splitFileName 'split.%04d' "$splitNum"。 ksh93足够聪明,可以自动优化命令替换中涉及的子shell; bash需要明确的语法来避免开销。

1

您可以使用此awk命令:

awk -F '|' 'NR<=3{ 
    hdr = hdr $0 RS 
} 
$1=="FORE"{ 
    close(fn) 
    fn="split-" ++n 
    printf "%s%s", hdr, $0 RS > fn 
} 
$1=="SD"{ 
    print > fn 
} 
END{close(fn)}' file 

在一个行:

awk -F '|' 'NR<=3{hdr = hdr $0 RS} $1=="FORE"{close(fn); fn="split-" ++n; printf "%s%s", hdr, $0 RS > fn} $1=="SD"{print > fn} END{close(fn)}' file 
+0

你正在为每个FORE做一个文件?我把这个问题看成每20mb需要一个文件,在FORE边界上分割。 (注意规范中的“分割文件大小”,以及伪代码中给出的20mb值)。 –

+0

我可能是错的,因为它在这里很晚:) – anubhava

+1

(awk *是一个很好的工具;我几乎试图更新和测试我的答案ksh93兼容性只是为了有希望保持适度的竞争力性能)。 –

0

的问题是用线条更容易像

FORE|20140508|20140214|\rSD|0|0039 - data|data|data|data|\rSD|0|0211 - data|data|data|data|\rSD|0|0039 - data|data|data|data|\rSD|0|0211 - data|data|data|data| 
FORE|20140508|20140214|\rSD|0|0039 - data|data|data|data|\rSD|0|0039 - data|data|data|data|\rSD|0|0211 - data|data|data|data| 

首先预处理与awk文件,将头文件保存在临时文件中并加入这些行从SD开始。 现在请拨打split -C 20m filename并附上您喜欢的参数。 Next tr "\r" "\n"分成不同的行,并在所有文件中添加标题。

编辑:预处理的加入线路可以

awk 'NR<=3 { print >> "filename.head" } 
    /^FORE/ { printf("%s%s",skipFirstNewline, $0); skipFirstNewline="\n" } 
    /^SD/ { printf("\r%s",$0) } 
    END{printf "\n" }' filename 

当你正在检查的结果,你会得到通过托架混淆返回\r来完成。因此,当您要检查输出时,请用rr临时替换\r

+0

非常好的主意。但只是在如何实现使用awk加入行的预处理部分而苦苦挣扎。还在搞清楚 – user3055262