简单的bash脚本按周编号分割csv文件

时间:2015-03-06 20:27:09

标签: bash awk

我正在尝试根据周数字段分隔大型管道分隔文件。该文件包含一整年的数据,因此有53周。我希望创建一个执行以下操作的循环:

1) check if week number is less than 10 - if it is paste a '0' in front
2) use grep to send the rows to a file (ie `grep '|01|' bigFile.txt > smallFile.txt` )
3) gzip the smaller file (ie `gzip smallFile.txt`)
4) repeat

是否有资源显示如何执行此操作?

编辑:

数据如下所示:

1|@gmail|1|0|0|0|1|01|com
1|@yahoo|0|1|0|0|0|27|com

我关心的专栏是右起第2位。

编辑2:

这是我正在使用的脚本,但它无法正常运行:

for (( i = 1; i <= 12; i++ )); do
    #statements
    echo 'i :'$i

    q=$i
    # echo $q
    # $q==10

    if [[ q -lt 10 ]]; then
        #statements
        k='0'$q
        echo $k
        grep '|$k|' 20150226_train.txt > 'weeks_files/week'$k
        gzip weeks_files/week $k

    fi
    if [[ q -gt 9 ]]; then
        #statements
        echo $q
        grep \'|$q|\' 20150226_train.txt > 'weeks_files/week'$q
        gzip 'weeks_files/week'$q
    fi


done

4 个答案:

答案 0 :(得分:3)

在awk中很简单......

awk -F'|' '{ print > ("smallfile-" $(NF-1) ".txt";) }' bigfile.txt

编辑:为&#34; original-awk&#34;添加了括号。

答案 1 :(得分:2)

你快到了。

#!/bin/bash

for (( i = 1; i <= 12; i++ )); do
    #statements
    echo 'i :'$i

    q=$i
    # echo $q
    # $q==10

    #OLD if [[ q -lt 10 ]]; then
    if [[ $q -lt 10 ]]; then
        #statements
        k='0'$q
        echo $k
#OLD        grep '|$k|' 20150226_train.txt > 'weeks_files/week'$k
        grep "|$k|" 20150226_train.txt > 'weeks_files/week'$k
#OLD    gzip weeks_files/week $k
        gzip weeks_files/week$k

    #OLD fi
    #OLD if [[ q -gt 9 ]]; then
    elif [[ $q -gt 9 ]] ; then
        #statements
        echo $q
        #OLD grep \'|$q|\' 20150226_train.txt > 'weeks_files/week'$q
        grep "|$q|" 20150226_train.txt > 'weeks_files/week'$q
       gzip 'weeks_files/week'$q
    fi
done

您并没有在变量值前面使用$。你只能使用k或q在shell关节替换功能中没有$,即z=$(( x+k)),或只是对(( k++ ))之类的变量进行操作。还有其他人。

您需要了解单引号和dbl引用之间的区别。如果想要替换变量的值,则需要使用dbl-quoting,如行

    grep "|$q|" 20150226_train.txt > 'weeks_files/week'$q

和其他人。

我猜你使用grep \'|$q|\' 20150226_train.txt试图获得$q的价值。

调试此类情况的方法是使用set -x设置shell调试选项(使用set +x将其关闭)。您将看到使用替换变量的值执行的每一行。高级调试需要echo "varof Interset now = $var"(打印语句)。此外,您可以使用set -vx(和set +vx)在执行代码之前查看每行或阻止,然后-x输出将显示实际执行的行。对于您的脚本,您会看到打印整个if ... elfi ...fi块,然后只显示-x输出的行以及变量值。即使经过多年的考虑,它也可能令人困惑。 ; - )

所以你可以通过前缀#OLD删除所有行,我希望你的代码能为你工作。

IHTH

答案 2 :(得分:2)

mkdir -p weeks_files &&
awk -F'|' '
    { file=sprintf("weeks_files/week%2d",$(NF-1)); print > file }
    !seen[file]++ { print file }
' 20150226_train.txt |
xargs gzip

如果订购了您的数据,以便给定周数的所有行都是连续的,那么您可以使其更简单,更有效:

mkdir -p weeks_files &&
awk -F'|' '
    $(NF-1) != prev { file=sprintf("weeks_files/week%2d",$(NF-1)); print file }
    { print > file; prev=$(NF-1) }
' 20150226_train.txt |
xargs gzip

答案 3 :(得分:1)

肯定有很多方法 - &#39; awk&#39;下面的行将重新格式化您的数据。如果你采用顺序方法,那么:

1)要重新格式化

awk -F '|' '{printf "%s|%s|%s|%s|%s|%s|%s|%02d|%s\n", $1, $2, $3, $4, $5, $6, $7, $8, $9}' SOURCE_FILE > bigFile.txt 

2)循环几个星期,创建一个zip文件小文件

for N in {01..53} 
do 
    grep "|${N}|" bigFile.txt > smallFile.${N}.txt
    gzip smallFile.${N}.txt
done

3)测试脚本显示重新格式化步骤

#!/bin/bash
function show_data {
# Data set w/9 'fields'
# 1| 2  |3|4|5|6|7| 8|9
cat << EOM
1|@gmail|1|0|0|0|1|01|com
1|@gmail|1|0|0|0|1|2|com
1|@gmail|1|0|0|0|1|5|com
1|@yahoo|0|1|0|0|0|27|com
EOM
}
###
function stars {
echo "## $@ ##"
}
###
stars "Raw data"
show_data
stars "Modified data"
#                                 1| 2| 3| 4| 5| 6| 7|   8|9 ##
show_data | awk -F '|' '{printf "%s|%s|%s|%s|%s|%s|%s|%02d|%s\n", $1, $2, $3, $4, $5, $6, $7, $8, $9}' 

示例运行:

$ bash test.sh
## Raw data ##
1|@gmail|1|0|0|0|1|01|com
1|@gmail|1|0|0|0|1|2|com
1|@gmail|1|0|0|0|1|5|com
1|@yahoo|0|1|0|0|0|27|com
## Modified data ##
1|@gmail|1|0|0|0|1|01|com
1|@gmail|1|0|0|0|1|02|com
1|@gmail|1|0|0|0|1|05|com
1|@yahoo|0|1|0|0|0|27|com