拆分基于图案
文件我有这将有以下模式拆分基于图案
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等的方式来实现这一点,而不是上面提到的高级逻辑。
几乎没有这么复杂的要求。这可以在完全没有外部命令的纯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需要明确的语法来避免开销。
您可以使用此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
你正在为每个FORE做一个文件?我把这个问题看成每20mb需要一个文件,在FORE边界上分割。 (注意规范中的“分割文件大小”,以及伪代码中给出的20mb值)。 –
我可能是错的,因为它在这里很晚:) – anubhava
(awk *是一个很好的工具;我几乎试图更新和测试我的答案ksh93兼容性只是为了有希望保持适度的竞争力性能)。 –
的问题是用线条更容易像
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
。
非常好的主意。但只是在如何实现使用awk加入行的预处理部分而苦苦挣扎。还在搞清楚 – user3055262
我注意到你最近的编辑 - 你有理由相信我的答案*不*已经做你要求的东西(重新:分裂只在一个FORE,保持作为一套与以下SDS)? –
嘿查尔斯。对于那个很抱歉。我起初没有注意到它,所以我继续编辑我的问题,认为我可能没有详细阐述,但是后来立即注意到你已经考虑了我的观点。 :)。我为此感谢你.. – user3055262
NP。唯一需要解释的问题是你是否想要在* FORE(如@ anubhava的答案)中分割,或者在20mb边界之后的第一个FORE中分割(就像我的答案一样)。 –