给定:一个大文本数据文件(例如CSV格式),第一行带有“特殊”行(例如字段名称)。
想要的:与coreutilssplit -l
命令等效,但另外的要求是,原始文件的标题行必须出现在每个结果片段的开头。
我猜想会合split
而head
为之吗?
给定:一个大文本数据文件(例如CSV格式),第一行带有“特殊”行(例如字段名称)。
想要的:与coreutilssplit -l
命令等效,但另外的要求是,原始文件的标题行必须出现在每个结果片段的开头。
我猜想会合split
而head
为之吗?
cat a b c > reconstructed
。文件中的多余行表示正常的重建方法不会复制原始文件。
unsplit --remove-header
实用程序的用途!但认真的说,split
如果要使用“重复标题”选项,则仍应默认使用其当前行为。如果确实需要,则只使用标头内容。
--keep-first N
一个不错的选择,split
在行和字节模式下都将非常有用
Answers:
这是robhruska的脚本清理了一下:
tail -n +2 file.txt | split -l 4 - split_
for file in split_*
do
head -n 1 file.txt > tmp_file
cat "$file" >> tmp_file
mv -f tmp_file "$file"
done
我删除wc
,cut
,ls
以及echo
在他们不必要的地方。我更改了一些文件名,使它们更有意义。我将其分成多行只是为了使其更易于阅读。
如果想花哨的话,可以使用mktemp
或tempfile
创建一个临时文件名,而不使用硬编码的文件名。
编辑
使用GNUsplit
可以做到这一点:
split_filter () { { head -n 1 file.txt; cat; } > "$FILE"; }; export -f split_filter; tail -n +2 file.txt | split --lines=4 --filter=split_filter - split_
出于可读性考虑:
split_filter () { { head -n 1 file.txt; cat; } > "$FILE"; }
export -f split_filter
tail -n +2 file.txt | split --lines=4 --filter=split_filter - split_
当--filter
指定时,split
运行用于每个输出文件的命令(在此情况下的函数,其必须导出)并设置变量FILE
,在命令的环境,到文件名。
过滤器脚本或函数可以对输出内容甚至文件名进行所需的任何操作。后者的示例可能是输出到可变目录中的固定文件名:> "$FILE/data.dat"
例如。
for $part in (split -l 1000 myfile); cat <(head -n1 myfile) $part > myfile.$part; done
split
在必要时不会输出stdout
。
split
可以将文件名输出到stdout,(只要我们正在讨论split
应该做什么:-)
这是Denis Williamson脚本的更强大的版本。该脚本会创建许多临时文件,如果运行不完整,将它们留在身边会很可惜。因此,让我们添加信号捕获功能(请参阅http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html,然后http://tldp.org/LDP/abs/html/debugging.html),删除我们的临时文件;无论如何,这是最佳做法。
trap 'rm split_* tmp_file ; exit 13' SIGINT SIGTERM SIGQUIT
tail -n +2 file.txt | split -l 4 - split_
for file in split_*
do
head -n 1 file.txt > tmp_file
cat $file >> tmp_file
mv -f tmp_file $file
done
将“ 13”替换为所需的任何返回码。哦,您可能仍然应该使用mktemp(正如某些人已经建议的那样),所以继续从陷阱行中的rm删除'tmp_file“。有关更多信号的信息,请参见信号手册页。
我喜欢marco的awk版本,此版本采用了简化的单行格式,您可以在其中轻松地将拆分分数指定为所需的粒度:
awk 'NR==1{print $0 > FILENAME ".split1"; print $0 > FILENAME ".split2";} NR>1{if (NR % 10 > 5) print $0 >> FILENAME ".split1"; else print $0 >> FILENAME ".split2"}' file
我真的很喜欢Rob和Dennis的版本,以至于我想改进它们。
这是我的版本:
in_file=$1
awk '{if (NR!=1) {print}}' $in_file | split -d -a 5 -l 100000 - $in_file"_" # Get all lines except the first, split into 100,000 line chunks
for file in $in_file"_"*
do
tmp_file=$(mktemp $in_file.XXXXXX) # Create a safer temp file
head -n 1 $in_file | cat - $file > $tmp_file # Get header from main file, cat that header with split file contents to temp file
mv -f $tmp_file $file # Overwrite non-header containing file with header-containing file
done
差异:
awk
而不是tail
由于awk
具有更好的性能head | cat
而不是两行使用GNU并行:
parallel -a bigfile.csv --header : --pipepart 'cat > {#}'
如果您需要在每个部分上运行命令,那么GNU Parallel也可以帮助您做到这一点:
parallel -a bigfile.csv --header : --pipepart my_program_reading_from_stdin
parallel -a bigfile.csv --header : --pipepart --fifo my_program_reading_from_fifo {}
parallel -a bigfile.csv --header : --pipepart --cat my_program_reading_from_a_file {}
如果要将每个CPU内核分为2个部分(例如24个内核= 48个相等大小的部分):
parallel --block -2 -a bigfile.csv --header : --pipepart my_program_reading_from_stdin
如果要分成10 MB的块:
parallel --block 10M -a bigfile.csv --header : --pipepart my_program_reading_from_stdin
下面是一个4衬纸,可用于将bigfile.csv拆分为多个较小的文件,并保留csv标头。仅使用内置的Bash命令(head,split,find,grep,xargs和sed),这些命令应可在大多数* nix系统上使用。如果您安装mingw-64 / git-bash,则在Windows上也应该可以使用。
csvheader =`head -1 bigfile.csv` 分割-d -l10000 bigfile.csv smallfile_ 查找。| grep smallfile_ | xargs sed -i“ 1s / ^ / $ csvheader \ n /” sed -i'1d'smallfile_00
逐行说明:
受到@Arkady对单线的评论的启发。
split
不显示文件名,但是该--additional-suffix
选项使我们可以轻松控制期望的内容rm $part
(假定没有带相同后缀的文件)MYFILE=mycsv.csv && for part in $(split -n4 --additional-suffix=foo $MYFILE; ls *foo); do cat <(head -n1 $MYFILE) $part > $MYFILE.$part; rm $part; done
证据:
-rw-rw-r-- 1 ec2-user ec2-user 32040108 Jun 1 23:18 mycsv.csv.xaafoo
-rw-rw-r-- 1 ec2-user ec2-user 32040108 Jun 1 23:18 mycsv.csv.xabfoo
-rw-rw-r-- 1 ec2-user ec2-user 32040108 Jun 1 23:18 mycsv.csv.xacfoo
-rw-rw-r-- 1 ec2-user ec2-user 32040110 Jun 1 23:18 mycsv.csv.xadfoo
并且当然head -2 *foo
会看到添加了标题。
一种简单但可能不那么优雅的方法:事先剪掉标题,分割文件,然后使用cat或正在读取文件的任何文件将每个文件的标题重新加入。如下所示:
split
,不是吗?