如何从文件中选择某些行(n,n + 4,n + 8,n + 12…)?


Answers:


28

使用AWK:

awk '!((NR - 1) % 4)' input > output

弄清楚这是如何工作的,留给读者练习。


感谢您参加这个简短的awk课程!
darxmurf

20
NR % 4 == 1会更清晰的IMO。
斯特凡Chazelas

12
同意@Stéphane; 这对我来说可能是有问题的,但是对于潜在的家庭作业问题,我会尝试使答案模糊不清...
Stephen Kitt,

@StephenKitt混淆了您的答案?真?这不是这样做的地方。
数据

22

使用split (GNU coreutils):

split -nr/1/4 input > output
  • -n生成CHUNKS输出文件

CHUNKS作为

  • r/K/N 使用循环分配,仅将N的第K个输出到stdout,而不拆分行/记录

1
精神震撼。这样的回答就是为什么我喜欢这个SE。谢谢!
user1717828

21

使用GNU sed

sed '1~4!d' < input > output

符合标准sed

sed -n 'p;n;n;n' < input > output

使用14in $n$i变量:

sed "$n~$i!d" # GNU only
awk -v n="$n" -v i="$i" 'NR >= n && (NR % i) == (n % i)'

7

添加强制性的perl解决方案:

perl -ne 'print if $. % 4 == 1' input > output

4

Python版本,只是为了好玩:

with open('input.txt') as f:
    for i, line in enumerate(f.readlines()):
        if i%4 == 0:
            print(line.strip())

enumerate(f)应该能够在消耗更少内存的情况下完成这项工作
iruvar,

@iruvar真整洁!以前从未意识到;将来会使用。随时将其编辑为该答案;我真的不会通过优化来维护它,因为其他Bash答案(尤其是这个)肯定是要走的路。
user1717828

如果要使用readlines(因此将整个文件插入内存),则可以使用f.readlines()[::4]来获取第四行。这样就可以使用了print(''.join(f.readlines()[::4]))
尼克·马特奥

3

POSIX sed:此方法使用posixly sed,因此可以在任何地方运行,或至少尊重posix的那些sed。

 $ sed -ne '
   /\n/!{
    H;s/.*//;x
   }

   :loop
       $bdone
       N;s/\n/&/4
       tdone
   bloop

   :done
   s/.//;P
 ' input.file

另一个是用于可扩展性目的的编程sed代码生成:

$ code=$(yes n | head -n 4 | paste -sd\; | sed s/n/p/)
$ sed -ne "$code" input.file

Perl:我们填充数组A直到大小为4。然后,我们打印其第一个元素并清除数组。

$ perl -pe '
   $A[@A] = @A ? <> : $_ while @A < 4;
   $_ = (splice @A)[0];
' input.file

1

scriptname filename skip(在您的情况下为4)调用它,方法是iter从文件的顶部拉线,然后仅输出最后一行。然后,它的增量iterskips和重复只要值iter未超过linesfile

#!/bin/bash
file="$1"
lines=`wc -l < "$file"`
skips="$2" || "4"
iter=1
while [ "$iter" -le "$lines" ]; do
 head "$file" -n $iter | tail -n 1
 iter=$(( $iter + $skips ))
done

1

纯重击:

mapfile -t lines < input
for (( i=0; i < ${#lines[@]}; i+=4 ))
do printf "%s\n" "${lines[$i]}"
done

mapfile是Bash 4中添加的内置函数,它将标准输入读取到数组中,此处命名为lines,每个条目一行。该-t选项将删除最后的换行符。

如果要从第4行开始每四行打印一次,则可以使用mapfile的callback选项在一个命令中执行此操作,该命令-C每隔多行运行提供的代码,间隔为-c。当前数组索引和要分配的下一行作为参数提供给代码。

mapfile -t -c4 -C 'printf "%.0s%s\n"' < input

这使用printf内置的;格式代码%.0s禁止显示第一个参数(索引),因此仅打印该行。

您可以使用同一命令从行1、2或3开始打印每四行,但input在将行送入之前必须先添加3、2或1行mapfile,我认为这比它值得的麻烦多。 。

这也适用:

mapfile -t lines < input
printf "%s%.0s%.0s%.0s\n" "${lines[@]}"

在这里,一次printf消耗数组的四个条目lines,只打印第一个,用跳过其他三个%.0s。我不喜欢这样,因为您必须手动调整格式字符串以获取不同的时间间隔或起点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.