【问题标题】:Splitting csv file into multiple files with 2 columns in each file将csv文件拆分为多个文件,每个文件有2列
【发布时间】:2019-01-16 17:22:08
【问题描述】:

我正在尝试拆分包含以下内容的文件 (testfile.csv):

1,2,4,5,6,7,8,9  
a,b,c,d,e,f,g,h  
q,w,e,r,t,y,u,i  
a,s,d,f,g,h,j,k  
z,x,c,v,b,n,m,z  

到文件中

1,2  
a,b  
q,w  
a,s  
z,x  

还有另一个文件

4,5    
c,d    
e,r    
d,f    
c,v    

但我似乎无法在 awk 中使用迭代解决方案来做到这一点。

awk -F, '{print $1, $2}'  
awk -F, '{print $3, $4}' 

为我做,但我想要一个循环解决方案。

我试过了

awk -F, '{ for (i=1;i< NF;i+=2) print $i, $(i+1) }' testfile.csv 

但它给了我一个单列。看来我正在迭代第一行,然后移动到第二行,跳过该特定行的所有其他元素。

【问题讨论】:

    标签: bash awk


    【解决方案1】:

    你可以使用cut:

    $ cut -d, -f1,2 file > file_1
    $ cut -d, -f3,4 file > file_2
    

    如果您要使用 awk,请务必设置 OFS,以便列保持为 CSV 文件:

    $ awk 'BEGIN{FS=OFS=","}
           {print $1,$2 >"f1"; print $3,$4 > "f2"}' file
    
    $ cat f1
    1,2
    a,b
    q,w
    a,s
    z,x
    $cat f2 
    4,5
    c,d
    e,r
    d,f
    c,v
    

    是否有一种快速而肮脏的方式来重命名具有第一行和第一列的结果文件(比如第一个文件是 1.csv,第二个文件是 4.csv

    awk 'BEGIN{FS=OFS=","}
         FNR==1 {n1=$1 ".csv"; n2=$3 ".csv"}
         {print $1,$2 >n1; print $3,$4 > n2}' file
    

    【讨论】:

    • 感谢您的回答。有没有一种快速而肮脏的方法来重命名具有第一行和第一列的结果文件(比如第一个文件是 1.csv,第二个文件是 4.csv?
    • 感谢您的编辑。这适用于 4 列。对于说 100 列是否有更“有效”的方法,我想提取 1+2,然后是 3+4,然后是 5+6,直到 97+98,最后是 99,100?我赞成您的回答,因为它非常整洁。
    • #!/bin/bash awk -F "," '{ for (i=1;i " tmp_" i}' $1 用于 tmp_* 中的文件名; do variable=awk -F, 'FNR==1 {print $1}' $filename tail -n +2 $filename > $variable.csv rm $filename done 完全是我丑陋的解决方案
    • 当你说'高效'的方式说 100 列?你需要定义它。写作效率高吗?读?执行?容易选择任何随机的列组吗? 高效在旁观者眼中...
    • 为清晰起见进行了编辑。 (对于说 100 列是否有更“有效”的方法,我想提取 1+2,然后是 3+4,然后是 5+6,直到 97+98,最后是 99,100?)
    【解决方案2】:
    awk -F, '{ for (i=1; i < NF; i+=2) print $i, $(i+1) > i ".csv"}' tes.csv
    

    为我工作。我试图在 bash 中获得输出,但结果完全混乱。

    【讨论】:

    • 谁能告诉我为什么stdout全乱了?
    • 不错的答案。请注意,如上所述,它适用于 gawk 和 mawk,但不适用于 BSD awk(包括 macOS)。我对此的看法是:awk 'BEGIN{FS=OFS=","} {for (i=1; i&lt;NF; i+=2) print $i, $(i+1) &gt; (i ".csv")}' input.csv。这设置了输出分隔符,但也将文件名声明放入括号中,BSD awk 确实 理解(并且其他人没有问题)。
    • 虽然这里不需要 100%,但为了消除任何可能的歧义,最好将重定向放在括号内:print $i, $(i+1) &gt; ( i ".csv")。想象一下以下 awk:echo "foo bar" | awk '{print $1 &gt; $2}'。您是要打印1 还是要打印文件bar 中的单词foo
    • 您可能需要随时关闭()输出文件,否则如果您有超过 20 个输出文件并且您没有使用,您将收到“打开文件过多”错误GNU awk。
    【解决方案3】:

    这在 bash 中是可行的,但它会比 awk 慢很多

    f=testfile.csv
    IFS=, read -ra first < <(head -1 "$f")
    for ((i = 0; i < (${#first[@]} + 1) / 2; i++)); do
        slice_file="${f%.csv}$((i+1)).csv"
        cut -d, -f"$((2 * i + 1))-$((2 * (i + 1)))" "$f" > "$slice_file"
    done
    

    【讨论】:

      【解决方案4】:

      使用 sed:

      sed -r '

      s/(.,.),./\1/w file1.txt

      s/.,.,(.,.),.
      /\1/w file2.txt' file.txt

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-16
        相关资源
        最近更新 更多