awk difference between 1 and {print}?

自古美人都是妖i 提交于 2021-01-28 22:23:45

问题


This comment on awk change once per file made me think 1 and {print} are equal in awk. But it is not.

awk '/^\S/ {core=0} /^_core/ {core=1} !core 1' views.view.who_s_online.yml|head
uuid: 50715f68-3b13-4a15-8455-853110fd1d8b
langcode: en
status: true
dependencies:
  module:
    - user
_core:
  default_config_hash: DWLCIpl8ku4NbiI9t3GgDeuW13KSOy2l1zho7ReP_Bg
id: who_s_online
label: 'Who''s online block'

Compare to (and this is what I wanted btw):

awk '/^\S/ {core=0} /^_core/ {core=1} !core {print}' views.view.who_s_online.yml|head
uuid: 50715f68-3b13-4a15-8455-853110fd1d8b
langcode: en
status: true
dependencies:
  module:
    - user
id: who_s_online
label: 'Who''s online block'
module: user
description: 'Shows the user names of the most recently active users, and the total number of active users.'

回答1:


The structure of an awk program is a series of conditions and actions:

condition { action }

The default value of condition is 1 (true), so actions without a condition always happen:

{ action } # is equivalent to
1 { action }

The default action is print, so quite often you will see a 1 in an awk script instead of { print }.

However, in your script, your condition is !core 1. This will negate the value of core, coerce it to a string and concatenate with the string "1". A non-empty string is always true, so every record will be printed.

If you want to only print records where core is false, then you can use !core as a condition by itself.




回答2:


Yes, they are the same.

These expressions are completely equivalent:

awk '1' file
awk '{print}' file
awk '42' file
awk '2342352' file
awk '{print $0}' file

Why? Because a True condition triggers awk's default action: to print the current record; that is, {print $0}.

Now, what is happening here?

You are using them in a different way. In one case, you are saying:

awk '{things...} !core 1' file
#                ^^^^^^^

In this case, !core is not doing anything. It reads as just awk '{things...} 1' file. Or better see Tom Fenech's explanation on it.

You can test it by executing both seq 10 | awk '/5/ {core++} 1' and seq 10 | awk '/5/ {core++} !core'. Both return all the numbers from 1 to 10. Instead, you would like to use seq 10 | awk '/5/ {core++} !core' to print from 1 to 4.

Notice also the difference with:

awk '{things...} !core; 1' file
#                     ^

By having this semi colon, this will trigger the action in !core (that is, to print the current record -line- if core evaluates to False) and then 1 will make it print all the records, no matter any condition. So seq 10 | awk '/5/ {core++} !core; 1' will print from 1 to 10, printing 1 to 4 twice.

On the other case you say:

awk '{things...} !core {print}' file
#                ^^^^^^^^^^^^^

This reads as: if core evaluates to False, then do print.

What is the reason behind them being equivalent?

This is because awk works on the syntax condition { action }, which can have { action } suppressed when it consists in the default action: {print $0}. This way, whenever you want an action to be always triggered, you can say either {print $0} or just use the condition part with a True condition, like 1, 42, a variable that you already set to a positive value, etc.

Then, this is also useful to make awk code more idiomatic: if you work with variables as a flag, you can say var and it will trigger the print whenever the flag is set to a True condition, likewise you do with core in your code. This way, these two awk expressions are equivalent:

awk '/5/ {core++} core'
awk '/5/ {core++} { if (core > 0) {print $0}}'
awk '{ if ($0~/5/) {core++}} { if (core > 0) {print $0}}'

See how using idiomatic code makes it look better? ;)

Check GNU Awk User's Guide → 7.3 Actions for a more technical explanation (and probably better wording than mine!):

An awk program or script consists of a series of rules and function definitions interspersed. (Functions are described later. See User-defined.) A rule contains a pattern and an action, either of which (but not both) may be omitted. The purpose of the action is to tell awk what to do once a match for the pattern is found. Thus, in outline, an awk program generally looks like this:

[pattern]  { action }
 pattern  [{ action }]
…
function name(args) { … }
…

An action consists of one or more awk statements, enclosed in braces (‘{…}’). Each statement specifies one thing to do. The statements are separated by newlines or semicolons. The braces around an action must be used even if the action contains only one statement, or if it contains no statements at all. However, if you omit the action entirely, omit the braces as well. An omitted action is equivalent to ‘{ print $0 }’:

/foo/  { }     match foo, do nothing — empty action
/foo/          match foo, print the record — omitted action


来源:https://stackoverflow.com/questions/39222230/awk-difference-between-1-and-print

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!