如何分割文件并保留每个部分的第一行?
- 2024-11-12 08:36:00
- admin 原创
- 28
问题描述:
给定:一个具有“特殊”第一行(例如字段名称)的大型文本数据文件(例如 CSV 格式)。
想要: coreutils 命令的等效命令split -l
,但另外要求原始文件的标题行出现在每个结果片段的开头。
我猜想某种混合物split
会head
起作用?
解决方案 1:
这是经过稍微清理的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"
例如。
解决方案 2:
此行代码将把大 csv 拆分成 999 条记录,并保留每条记录顶部的标题行(因此 999 条记录 + 1 个标题 = 1000 行)
cat bigFile.csv | parallel --header : --pipe -N999 'cat >file_{#}.csv'
根据 Ole Tange 的回答。
请参阅评论以获取有关安装并行的一些提示
解决方案 3:
您可以使用 GNU coreutils split >= 8.13 (2011) 中的新 --filter 功能:
tail -n +2 FILE.in | split -l 50 - --filter='sh -c "{ head -n1 FILE.in; cat; } > $FILE"'
解决方案 4:
您可以使用[mg] awk:
awk 'NR==1{
header=$0;
count=1;
print header > "x_" count;
next
}
!( (NR-1) % 100){
count++;
print header > "x_" count;
}
{
print $0 > "x_" count
}' file
100 是每个切片的行数。它不需要临时文件,可以放在一行上。
解决方案 5:
我对 Bash-fu 还只是个新手,但我能够编写出这个只有两个命令的怪物。我相信还有更优雅的解决方案。
$> tail -n +2 file.txt | split -l 4
$> for file in `ls xa*`; do echo "`head -1 file.txt`" > tmp; cat $file >> tmp; mv -f tmp $file; done
这是假设您的输入文件是file.txt
,您没有使用 的prefix
参数split
,并且您正在一个目录中工作,该目录中没有任何其他以 的split
默认xa*
输出格式开头的文件。此外,将“4”替换为您所需的分割线大小。
解决方案 6:
使用 GNU Parallel:
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
解决方案 7:
下面是一个 4 行代码,可用于将 bigfile.csv 拆分为多个较小的文件,并保留 csv 标头。仅使用内置 Bash 命令(head、split、find、grep、xargs 和 sed),这些命令应适用于大多数 *nix 系统。如果您安装了 mingw-64 / git-bash,也应适用于 Windows。
csvheader=`head -1 大文件.csv`
split -d -l10000 bigfile.csv smallfile_
查找 .|grep smallfile_ | xargs sed -i "1s/^/$csvheader
/"
sed -i ‘1d’ smallfile_00
逐行解释:
将标头捕获到名为csvheader的变量中
将bigfile.csv拆分为多个以smallfile_为前缀的小文件
查找所有小文件并使用xargs和sed -i将 csvheader 插入第一行。请注意,您需要在“双引号”内使用 sed 才能使用变量。
第一个名为 smallfile_00 的文件现在在第 1 行和第 2 行有冗余标头(来自原始数据以及第 3 步中的 sed 标头插入)。我们可以使用 sed -i '1d' 命令删除冗余标头。
解决方案 8:
这是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”。请参阅信号手册页以了解更多要捕获的信号。
解决方案 9:
我喜欢 awk 版本的 marco,它采用了简化的单行代码,您可以在其中轻松指定所需的分割分数:
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
解决方案 10:
我真的很喜欢 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
差异:
in_file 是要拆分维护标题的文件参数
由于性能更好,
awk
因此使用tail
`awk`拆分为 100,000 行文件,而不是 4 行
分割文件名将是输入文件名附加下划线和数字(最多 99999 - 来自“-d -a 5”分割参数)
使用 mktemp 安全地处理临时文件
使用
head | cat
单行而不是双行
解决方案 11:
受到@Arkady 对一句话的评论的启发。
MYFILE 变量只是为了减少样板
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
看到标题被添加了。
解决方案 12:
一种简单但可能不那么优雅的方法:预先切断标题,拆分文件,然后使用 cat 或正在读取它的任何文件重新连接每个文件的标题。因此类似于:
head -n1 文件.txt > 标题.txt
拆分-l 文件.txt
猫头.txt f1.txt
解决方案 13:
使用以下代码我得到了更好的结果,每个拆分文件都会有一个标题,并且生成的文件都会有一个规范化的名称。
export F=input.csv && LINES=3 &&\nexport PF="${F%.*}_" &&\nsplit -l $LINES "${F}" "${PF}" &&\nfor fn in $PF*
do
mv "${fn}" "${fn}.csv"
done &&\nexport FILES=($PF*) && for file in "${FILES[@]:1}"
do
head -n 1 "${F}" > tmp_file
cat "$file" >> tmp_file
mv -f tmp_file "${file}"
done
输出
$ wc -l input*
22 input.csv
3 input_aa.csv
4 input_ab.csv
4 input_ac.csv
4 input_ad.csv
4 input_ae.csv
4 input_af.csv
4 input_ag.csv
2 input_ah.csv
51 total
解决方案 14:
迟到了...
阅读完所有这些内容后,我将其添加到我的 bashrc 中:
split_csv_file() {
_split_csv_filter() {
{ head -n 1 "${1}"; cat; } >| "$FILE";
}
export -f _split_csv_filter
local file_name="${1##*/}"
local file_base="${file_name%.*}"
local chunks="${2}"
echo "$file_name $file_base $chunks"
tail -n +2 "${1}" | split -n l/"${chunks}" -d --filter="_split_csv_filter ${1}" - "${file_base}." --additional-suffix=.csv
}
这使我能够将# split_csv_file sample.csv 25
csv 文件拆分成 25 个部分。感谢之前的所有回答,它们让我找到了这个非常方便的 bash 函数。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件