2017-05-05 41 views
0

我有以下的测试文件:将一个文件分成单独的基于行号

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 

我想它在每个文件都包含以前的文件的第一行的最后一行的方式分开。例如:

file 1: 
1 
2 
3 
4 
5 
file2: 
5 
6 
7 
8 
9 
file3: 
9 
10 
11 
12 
13 
file4: 
13 
14 
15 
16 
17 
file5: 
17 
18 
19 
20 

这将使4个文件包含5行和1个文件与4行。

作为第一步,我试着测试下面的命令,我只写了第一个包含前5行的文件。我不明白为什么在if声明中的awk命令,而不是打印第5行,它打印整个20?

d=$(wc test) 
a=$(echo $d | cut -f1 -d " ") 
lines=$(echo $a/5 | bc -l) 
integer=$(echo $lines | cut -f1 -d ".") 
for i in $(seq 1 $integer); do 
start=$(echo $i*5 | bc -l) 
var=$((var+=1)) 
echo start $start 
echo $var 
if [[ $var = 1 ]]; then 
    awk 'NR<=$start' test 
fi 
done 

谢谢!

+0

你试过'split'? – 123

+0

@ 123我添加了一个解释这个的编辑。 – Homap

+0

@Ed Morton对不起,感到困惑。我最初的目标是sthg else(现在在编辑版本中解释过),但我只想询问我的代码中的错误,所以我写了不同的问题。现在,我希望它更清楚。 – Homap

回答

2
$ ls 
$ 
$ seq 20 | awk 'NR%4==1{ if (out) { print > out; close(out) } out="file"++c } {print > out}' 
$ 
$ ls 
file1 file2 file3 file4 file5 

$ cat file1 
1 
2 
3 
4 
5 
$ cat file2 
5 
6 
7 
8 
9 
$ cat file3 
9 
10 
11 
12 
13 
$ cat file4 
13 
14 
15 
16 
17 
$ cat file5 
17 
18 
19 
20 

如果你曾经尝试使用一个shell循环再处理文本,请务必阅读https://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice第一至少了解一些原因,而不是AWK使用。要学习awk,请阅读Arnold Robbins编写的第4版Effective Awk Programming。

哦。并且为什么你的awk命令awk 'NR<=$start' test不起作用 - awk不是shell,它没有比C程序更多的对shell变量的访问(反之亦然)。要使用名为start的shell变量的值初始化一个名为awkstart的awk变量,然后在脚本中使用该awk变量,那么将执行awk -v awkstart="$start" 'NR<=awkstart' test。 awk变量也可以被命名为start或其他任何明智的东西 - 它与shell变量的名称完全无关。

3

为什么不使用POSIX工具包中提供的split util。它有一个选项分裂的行数,你可以把它作为5

split -l 5 input-file 

man split页面,

-l, --lines=NUMBER 
     put NUMBER lines/records per output file 

需要注意的是,-lPOSIX compliant也。

+0

Nit挑选:分裂不是一个bash的事情;这是POSIX强制实用程序。 – Jens

+0

@Jens:是的,不知道我输入了它;) – Inian

+0

原来的问题,基本上是'每4行打印5行',包含了行重叠,这是行不通的。 – ULick

0

你可以通过删除unneccesary echocutbc提高你的代码,并像这样做

#!/bin/bash 
for i in $(seq $(wc -l < test)); do 
    ((i % 4 != 1)) && continue 
    tail +$i test | head -5 > "file$((1+i/4))" 
done 

但还是awk的解决方案要好得多。只读取一次文件,并根据现成的信息(如床单编号)采取行动是一条路。在外壳必须计算线路,有没有办法绕过它。 awk会免费给你(和很多其他的东西)。

0

使用split

$ seq 20 | split -l 5 
$ for fn in x*; do echo "$fn"; cat "$fn"; done 
xaa 
1 
2 
3 
4 
5 
xab 
6 
7 
8 
9 
10 
xac 
11 
12 
13 
14 
15 
xad 
16 
17 
18 
19 
20 

或者,如果你有一个文件:

$ split -l test_file 
相关问题