22

AWK tips 之移动文件中的指定行 - 暗无天日

 5 years ago
source link: https://www.lujun9972.win/blog/2020/05/15/awk-tips-%E4%B9%8B%E7%A7%BB%E5%8A%A8%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E6%8C%87%E5%AE%9A%E8%A1%8C/index.html?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

AWK tips 之移动文件中的指定行

https://www.datafix.com.au/BASHing/2020-05-13.html 上看到的 AWK 技巧,记录一下。

假设有这个一个文件:

SaleID|Class|Item|Count|UnitP|TotalP
146|fish|BG fillets|3|15.00|45.00
2785|fruit|banana|1|0.45|0.45
0039|fruit|banana|1|0.45|0.45
119|meat|liver paste|1|2.10|2.10
6253|veg|carrot bunch|2|4.90|9.80
8847|fish|tin tuna|4|1.50|6.00
3776|veg|pak choy|2|2.50|5.00
295|fruit|apple|6|0.94|5.64
534|fish|tin tuna|1|1.50|1.50
1221|meat|pork slices|8|4.20|33.60 

现在想把 SaleID 为 295 的这条记录移动到 0039 后面,用 AWK 如何实现?

这里的技巧在于对同一个文件遍历两次,第一次找出待移动的记录并记录到某个变量中,第二次在恰当的位置输出它。最后的解决方法为:

awk -F"|" 'FNR==NR {if ($1=="295") {x=$0}; next} \
$1=="0039" {$0=$0 RS x} $1!="295" {print}' demo demo
SaleID|Class|Item|Count|UnitP|TotalP
146|fish|BG fillets|3|15.00|45.00
2785|fruit|banana|1|0.45|0.45
0039|fruit|banana|1|0.45|0.45
295|fruit|apple|6|0.94|5.64
119|meat|liver paste|1|2.10|2.10
6253|veg|carrot bunch|2|4.90|9.80
8847|fish|tin tuna|4|1.50|6.00
3776|veg|pak choy|2|2.50|5.00
534|fish|tin tuna|1|1.50|1.50
1221|meat|pork slices|8|4.20|33.60 

这里 FNR==NR {第一个文件的处理逻辑;next} 第二个文件的处理逻辑 是一种常见的搭配,用来先通过第一个文件构造必要的变量,然后利用这些构造出的变量来处理第二个文件。

这里的关键在于,第一个文件的处理过程一定要以 next 结尾,这样才会让 AWK 中断后面的模式匹配和操作,直到遍厉完第一个文件的内容。

当然,如果我们直到被移动记录的行数和插入的位置的话,也可以直接使用 FNR 作为匹配条件,例如上面的操作可以改为

awk 'FNR==NR {if (NR==9) {x=$0}; next} \
 FNR==4 {$0=$0 RS x} FNR!=9 {print}' demo demo
SaleID|Class|Item|Count|UnitP|TotalP
146|fish|BG fillets|3|15.00|45.00
2785|fruit|banana|1|0.45|0.45
0039|fruit|banana|1|0.45|0.45
295|fruit|apple|6|0.94|5.64
119|meat|liver paste|1|2.10|2.10
6253|veg|carrot bunch|2|4.90|9.80
8847|fish|tin tuna|4|1.50|6.00
3776|veg|pak choy|2|2.50|5.00
534|fish|tin tuna|1|1.50|1.50
1221|meat|pork slices|8|4.20|33.60 

在进一步,我们可以将这段 AWK 代码封装成一个函数:

shiftline()
{
    awk -v target="$2" -v putafter="$3" 'FNR==NR {if (NR==target) {x=$0; next} else next} FNR==putafter {$0=$0 RS x} FNR!=target {print}' "$1" "$1"
}

shiftline demo 9 4
SaleID|Class|Item|Count|UnitP|TotalP
146|fish|BG fillets|3|15.00|45.00
2785|fruit|banana|1|0.45|0.45
0039|fruit|banana|1|0.45|0.45
295|fruit|apple|6|0.94|5.64
119|meat|liver paste|1|2.10|2.10
6253|veg|carrot bunch|2|4.90|9.80
8847|fish|tin tuna|4|1.50|6.00
3776|veg|pak choy|2|2.50|5.00
534|fish|tin tuna|1|1.50|1.50
1221|meat|pork slices|8|4.20|33.60 

</div


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK