我必须根据以下控制文件从源文件动态生成文件。
control_file.txt
1,3,5,-1,8,-1,4
控制文件包含我从源文件中需要的列的位置。
例如:1列、3列、5列、空白列(-1表示空白列)等等。
我写了一个shell,从控制文件中一一读取位置,生成多个文件。然后最后使用粘贴命令生成新文件,以防我创建触摸文件的-1值。根据文件顺序,通过选项粘贴ls-v
。
所以我现有的外壳如下所示:
if [ position != -1 ]
then
cut -d, -f$position > file_$var.csv
else
touch file_$var.csv
fi
paste -d, $(ls -v file_*.csv) > newe_file.csv
我希望有一种方法可以最大限度地减少文件的 I/O,我正在寻找以下内容:
cut -d, -f1,3,5 > file1.csv
touch file2.csv
cut -d, -f8 > file3.csv
touch file4.csv
cut -d, -f4 > file5.csv
或者更好的解决方案会很棒。
源文件中的列数将达到数百列。
预期成绩:
input-file is sample.csv
col1,col2,col3,col4,col5,col6,col7,col8
1,2,3,4,5,6,7,8
9,10,11,12,13,14,15,16
输出.csv:
col1,col3,col5,-1,col8,-1,col4
1,3,5,,8,,4
9,11,13,,16,,12
输出.csv基于controlfile.txt
答案1
另一个答案,比其他答案简单一点:
#!/bin/bash
fields=$(sed -r -e 's/-1/ /g' -e 's/,/ FS /g' \
-e 's/([0-9]+)/\$\1/g' control_file.txt)
awk -F, "{print ${fields}}" $1
第一个命令转换control_file.txt
为合适的awk
命令:
$1 FS $3 FS $5 FS FS $8 FS FS $4
运行它:
$ ./script.sh input.csv
col1,col3,col5,,col8,,col4
1,3,5,,8,,4
9,11,13,,16,,12
在你的另一个样本上:
$ ./script.sh sample.csv
BP ID,CurrentMonetary balance ,Provider contract id,,End Date,,charge Plan names
1100001538,251,00000000000000000141,,18-Oct-12,,[B2] R2 LTE CHARGE PLAN
1100003404,45.22,00000000000000009349,,23-Nov-13,,B0.3 ECS_CHARGE_PLAN DROP1 V3
答案2
awk 文件
BEGIN { sp="-1" ; FS="," ; }
FILENAME == "control.txt" { for (i=1;i<=NF;i++) col[i]=$i ; next ;}
FILENAME != "control.txt" {
comma="" ;
for (i=1;i<NF;i++) {
c=col[i] ;
if (col[i]!=-1) printf "%s%s",comma,$c ;
else printf "%s%s",comma,sp ;
comma="," ;
}
printf "\n" ;
sp="" ;
}
运行
awk -f a.awk control.txt sample.txt
col1,col3,col5,-1,col8,-1,col4
1,3,5,,8,,4
9,11,13,,16,,12
基本上,control.txt 中的第一行获取要打印的列。
答案3
echo '1,2,3,4,5,6,7,8' |
sed 's/[^,]*//7;s///6;s///2;s/,,/,/
s/\([^,]*\),\([^,]*\),,.*,\(.*\)/\2,,\3,,\1/'
这会删除字段 7、6、2 的内容。接下来,它删除第一个空白字段。然后它交换最后三个非空字段,如 2,,3,,1。
输出
1,3,5,,8,,4
并运行您的示例数据:
BP ID,CurrentMonetary balance ,Provider contract id,,End Date,,charge Plan names
1100001538,251,00000000000000000141,,18-Oct-12,,[B2] R2 LTE CHARGE PLAN
1100003404,45.22,00000000000000009349,,23-Nov-13,,B0.3 ECS_CHARGE_PLAN DROP1 V3
话又说回来,只要您可以验证您的分隔符,您就可以能只需使用外壳:
set -f; IFS=,
set -- $(cat file; echo "$IFS")
while [ $# -gt 8 ]
do printf %s\\n "$1,$3,$5,,$8,,$4"
shift "$(($#>7?8:$#))"
done
使用 shell 选项,字段可以包含除分隔符之外的任何内容。只要有分隔符,<space><tab><newline>
空字段以外的字段就会被保留。它们包含的任何字符(包括这三个空白字符中的任何一个)都会被保留。这里我用了逗号。您只需要足够的内存来容纳该文件。