Ruby中与Awk的FNR==NR等价的是什么?

ecbunoof  于 2023-02-03  发布在  Ruby
关注(0)|答案(1)|浏览(99)

Awk有内置变量FNRNR,用于表示从当前文件读取的记录数(通常是行数)和总数。
在awk中,通常有:

$ awk 'FNR==NR {first file lines; next } {process remaining lines } f1 f2

通常,f1包含决定如何处理剩余文件的值(关键字、行号等)。
Ruby具备了成为一种出色的文本处理语言的条件,Ruby有$.作为awk的NR的等价物,FNR的等价物是什么?

50few1ms

50few1ms1#

给定:

$ head f?.txt
==> f1.txt <==
line 1
line 2

==> f2.txt <==
line 3
line 4

Ruby有一个ARGF stream(如果你想体验一下Perly,可以别名为$<),它可以读取STDIN或者从命令行打开一个文件,行为与awk相同:

$ awk '{
    printf("FILENAME: %s, FNR: %s, NR: %s, %s\n", FILENAME, FNR,NR,$0)}
' f?.txt
FILENAME: f1.txt, FNR: 1, NR: 1, line 1
FILENAME: f1.txt, FNR: 2, NR: 2, line 2
FILENAME: f2.txt, FNR: 1, NR: 3, line 3
FILENAME: f2.txt, FNR: 2, NR: 4, line 4

$ ruby -lne '
    printf("FILENAME: %s, FNR: %s, NR: %s, %s\n", $<.file.path, $<.file.lineno, $., $_)
' f?.txt
FILENAME: f1.txt, FNR: 1, NR: 1, line 1
FILENAME: f1.txt, FNR: 2, NR: 2, line 2
FILENAME: f2.txt, FNR: 1, NR: 3, line 3
FILENAME: f2.txt, FNR: 2, NR: 4, line 4

如果你想同时读取STDIN和一个文件,你可以使用-作为文件占位符:

$ echo '123' | awk '1' - <(echo 456)
123
456
$ echo '123' | awk '1' <(echo 456) -
456
123

$ echo '123' | ruby -lne 'puts $_' - <(echo 456)
123
456
$ echo '123' | ruby -lne 'puts $_' <(echo 456) -
456
123

更多对应变量:

╔══════════╦═══════════════════╦═════════════════════════════════════════╗
║   awk    ║       ruby        ║                 comment                 ║
╠══════════╬═══════════════════╬═════════════════════════════════════════╣
║ $0       ║ $_                ║ unsplit record (line usually)           ║
║ NF       ║ $F.length         ║ Number of fields from autosplit         ║
║ FNR      ║ ARGF.file.lineno  ║ Number records read from current source ║
║ NR       ║ ARGF.lineno or $. ║ Total number of records so far          ║
║ (magic)  ║ ARGF or $<        ║ stream from either STDIN or a file      ║
║ $1..$NF  ║ $F[0]..$F[-1]     ║ First to last field from autosplit      ║
║ FS       ║ $;                ║ Input field separator                   ║
║ RS       ║ $/                ║ Input record separator                  ║
║ FILENAME ║ $<.file.path      ║ Filename of file being processed        ║
╚══════════╩═══════════════════╩═════════════════════════════════════════╝

因此,如果您在f1中有一个行号列表,并且您希望使用这些行号索引一个文本文件(您可以使用awksed来完成此操作),则可以使用Ruby。
给定:

$ echo "1
2
44
2017" >f1
$ seq 10000 | awk '{print "Line", $1}' >f2

awk中,您可以执行以下操作:

$ awk 'FNR==NR{ln[$1]; next} 
       FNR in ln'    f1 f2

在Ruby中,您可以执行以下操作:

$ ruby -lane 'BEGIN{h=Hash.new}
              if $<.file.lineno == $<.lineno
                 h[$F[0].to_i]=true
                 next
              end
              puts $_ if h[$<.file.lineno]' f1 f2

两者均打印:

Line 1
Line 2
Line 44
Line 2017

这个例子的awk版本大约快5倍(go awk),但是Ruby版本可以轻松支持awk无法支持的输入,比如JSON、XML、复杂的csv等等

相关问题