按周数拆分csv文件的简单bash脚本

按周数拆分csv文件的简单bash脚本,bash,awk,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

我正在尝试根据周数字段分隔一个以管道分隔的大文件。该文件包含全年的数据,因此有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:

以下是我正在使用的脚本,但它无法正常工作:

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
for((i=1;i'weeks\u files/week')$k
gzip周文件/周$k
fi
如果[[q-gt 9]];则
#声明
echo$q
grep\''124;$q\'20150226\u train.txt>'weeks\u files/week'$q
gzip“周文件/周”$q
fi
完成
在awk中非常简单

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

编辑:为“原始awk”添加括号。

当然有许多方法-下面的“awk”行将重新格式化您的数据。如果您采用顺序方法,则:

1) awk需要重新格式化

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) 周而复始,创建一个小文件并压缩它

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}' 
你快到了

#!/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
等等

我猜您使用
grep\'$q |\'20150226\u train.txt
是为了获取
$q
的值

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

因此,您可以遍历并删除所有前缀为#OLD的行,我希望您的代码能够为您工作

IHTH

如果对数据进行排序,使给定周数的所有行都是连续的,则可以使其更简单、更高效:

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

文件是什么样子的?请提供数据示例。Just bash可能是错误的工具。Awk或Perl可能会工作得更好。@mklement0:你是对的-这只是为了调试以获得一位数和两位数的混合。@screechOwl:没有一个答案对你有用吗?这确实是迄今为止最简单也是最有效的解决方案;请注意,至少对于BSD awk,您需要使用
(“smallfile-“$(NF-1)”.txt”)
(用括号括起来)才能工作(GNU awk和mawk没有括号也可以)。如果你加入了
gzip smallfile-*
,你就有了一个完整的解决方案。(附录,在OP之后添加了生成输出文件的代码,这意味着一个命名方案:这个解决方案没有做的事情-除了一般名称和位置细节-是0-pad成为文件名一部分的索引。)@mklement0除外,示例原始文件和grep命令所需的文件已经有零,因此不需要编辑该值,因为它被视为字符串。但是如果输入有一个混合,awk有一个sprintf函数,你可以使用。你完全正确:OP的样本输入数据和代码表明输入周数确实已经是零填充的(正如我自己在其他地方所指出的那样——去吃我的记忆药片)。可能不需要重新格式化输入文件-请注意,OP仅努力创建0填充索引以进行灰显。Bash3.x用户需要注意的是:
{01..53}
不会创建
01
02
,…,而是
1
2
,…-要使零填充起作用,需要bash4+;我当然喜欢awk解决方案,但是它并没有真正完成请求,也没有解释(是的,如果您已经对awk/bash脚本有点熟悉,也许这是显而易见的,但不是因为noob)。是的,不幸的是,单行awk解决方案缺少解释,而且不完整(我在一篇评论中添加了缺少的
gzip
命令,但是一个完整的、充分解释的答案当然更可取)。如果你解释你的答案,OP会略过解释,说“谢谢”如果他们自己去调查,试图理解它,然后提出问题,那么他们会学到更多,尤其是在哪里可以找到工具上的文档因此,他们可以了解的不仅仅是这一个答案。你还浪费了相当多的时间来解释那些对OP来说可能非常明显的事情。我知道不是每个人都同意这种观点:-)@EdMorton:我听到了,但在这一光谱的极端末端,存在着充满奥秘的无法解释的答案,这些答案让经验较少的人放弃去理解它们。此外,如果读者不愿意学习,一个(部分)无法解释的答案不会神奇地让他们进行自己的调查。Re“你还浪费了相当一部分时间来解释那些对OP来说可能非常明显的事情”:这是一种确定的可能性,但请记住,答案绝不只是针对OP,其他(以后)读者可能有非常不同的技能水平。感谢bash的合理建议,但值得指出的是,在纯bash中解决这个问题是错误的方法,正如@mklement0的简单性所证明的那样。@mklement0,是的,我同意user3710044是更好的解决方案。不得不跑完,不能完成。我认为代码大小本身就说明了问题。如果O.P.只是在学习
bash
的工作原理,那么这是一个不错的非初学者项目。我喜欢Dale_Reagen的试验台方法(因为
    grep "|$q|" 20150226_train.txt > 'weeks_files/week'$q
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