问题描述
t_#_3_0 v_0_17 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2
t_#_3_1 v_0_144 v_1_17 v_2_20 u_0_1 u_0_2 u_1_2
t_#_3_2 v_0_143 v_1_233 v_2_238 u_0_1 u_0_2 u_1_2
t_#_3_3 v_0_20 v_1_253 v_2_275 u_0_1 u_0_2 u_1_2
t_#_3_4 v_0_144 v_1_209 v_2_90 u_0_1 u_0_2 u_1_2
t_#_3_5 v_0_144 v_1_209 v_2_30 u_0_1 u_0_2 u_1_2
t_#_3_6 v_0_19 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2
t_#_3_7 v_0_20 v_1_7 v_2_78 u_0_1 u_0_2 u_1_2
t_#_3_8 v_0_16 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2
t_#_3_9 v_0_15 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2
我想逐行拆分它,并将第一个字符串保留为新文件的标题。我想要的输出应该像这样。
file 1: t_#_3_0.txt (inside located line - t_#_3_0 v_0_17 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2)
file 2: t_#_3_1.txt
file 3: t_#_3_2.txt
感谢您的建议!
谢谢!
Olha
解决方法
使用GNU awk:
awk '{name=$1 ".txt"; print >name; close(name)}' file
变量name
包含第一列后缀.txt
的内容。 print >name
将完整的当前行写入文件name
。
我对要求的理解:
- 源文件中的每一行都将被复制到一个新文件中
- 新文件以字段(第1列)的内容命名
一个awk
解决方案(假设原始数据位于文件file.all
中)
$ awk '{ fn=$1".txt" ; print > fn ; close (fn) } ' file.all
$ for f in t*#*txt
do
echo "+++++++++++++ $f"
cat $f
done
+++++++++++++ t_#_3_0.txt
t_#_3_0 v_0_17 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2
+++++++++++++ t_#_3_1.txt
t_#_3_1 v_0_144 v_1_17 v_2_20 u_0_1 u_0_2 u_1_2
+++++++++++++ t_#_3_2.txt
t_#_3_2 v_0_143 v_1_233 v_2_238 u_0_1 u_0_2 u_1_2
+++++++++++++ t_#_3_3.txt
t_#_3_3 v_0_20 v_1_253 v_2_275 u_0_1 u_0_2 u_1_2
+++++++++++++ t_#_3_4.txt
t_#_3_4 v_0_144 v_1_209 v_2_90 u_0_1 u_0_2 u_1_2
+++++++++++++ t_#_3_5.txt
t_#_3_5 v_0_144 v_1_209 v_2_30 u_0_1 u_0_2 u_1_2
+++++++++++++ t_#_3_6.txt
t_#_3_6 v_0_19 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2
+++++++++++++ t_#_3_7.txt
t_#_3_7 v_0_20 v_1_7 v_2_78 u_0_1 u_0_2 u_1_2
+++++++++++++ t_#_3_8.txt
t_#_3_8 v_0_16 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2
+++++++++++++ t_#_3_9.txt
t_#_3_9 v_0_15 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2
,
这些结果让我感到惊讶。 :)
sed
只是从工具箱中拉出一些奇怪的东西,作为为什么您应该不时评估方法的示例...
$: time sed -En 's/^([^ ]+)( .*)$/printf "%s%s\n" "\1" "\2" > \1.txt/e' file
real 0m0.859s
user 0m0.183s
sys 0m0.480s
我认为这样做会很慢,但是为了以防万一,在工具箱中安装它还是很好的。不要用钳子钉指甲。
awk
$: time awk '{ fn=$1".txt" ; print > fn ; close (fn) } ' file
real 0m0.141s
user 0m0.031s
sys 0m0.077s
出乎意料的更快,对于较大的文件可能会很多。
但是让我感到惊讶的人-
纯bash
$: time while read line; do echo "$line" > "${line%%[ ]*}"; done < file
real 0m0.015s
user 0m0.000s
sys 0m0.016s
注意-编辑以使用空格和/或制表符
"${line%%[ ]*}"
在方括号[ ]
之间有一个空格和一个制表符作为字段定界符。
我认为这里节省的时间是文件管理的开销。众所周知read
的运行速度很慢,但是我想操作系统可以很好地处理自己的I / O。
也许有人可以进行更深入的分析?
将测试详细说明为1万条记录的样本,大大缩小了bash
和awk
之间的差距-
$: for x in {0..9999}; do echo "t_${x}_3_0 v_0_17 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2"; done >| file
$: time while read line; do echo "$line" > "${line%% *}"; done < file
real 0m24.022s
user 0m2.360s
sys 0m11.938s
$: time awk '{ fn=$1".txt" ; print > fn ; close (fn) } ' file
real 0m27.284s
user 0m1.312s
sys 0m12.656s
$: $: time sed -En 's/^([^ ]+)( .*)$/printf "%s%s\n" "\1" "\2" > \1.txt/e' file
real 13m28.503s
user 1m48.374s
sys 8m22.970s
我怀疑与较小的数据集有很多不同之处,也许是awk
的编译时间?
测试100k以确认-
$: wc -c file # >5.5MB
5788890 file
bash
:
real 8m42.666s
user 0m28.671s
sys 2m34.781s
awk
:
real 8m15.096s
user 0m15.546s
sys 2m35.421s
我真的很惊讶它们之间的差别很小。
我认为是因为大多数时候 是文件I / O操作。