-3

I found the below awk command to sequentially replace a particular line in a file, but i would like to know how this works.

Input:-

DS: 1
DS: 1
DS: 1
DS: 1
DS: 1
DS: 1
DS: 1

output:-

DS: 1
DS: 2
DS: 3
DS: 1
DS: 2
DS: 3
DS: 1
DS: 2
DS: 3

Awk Command:-

awk '$1 ~ /DS:/ {$NF=((c++ % count) + 1)} 1' count=3
1

I have reasons to believe that the working awk command is

awk -v count=3 '/DS:/ {$NF=((c++ % count) + 1)} 1' input

where input is the input file. Also I think there should be 9 lines in the input file instead of 7 to generate the output specified in the question.

Here is how it works.

First, the option -v count=3 assigns 3 to the awk variable count. If it were written the way it is written as in the question (count=3 at the end of the command), 3 would be assigned to a shell variable and will not be accessible by awk and will result in a division by zero error since count will be implicitly initialized to 0.

In

/DS:/ {$NF=((c++ % count) + 1)}

The /DS:/ part is the condition for the block in braces. It stands for the regex DS:, which can only match the string DS:. This condition matches all the lines that contains DS:.

For all these lines, the variable c is incremented and then taken modulus count. Since we have no explicit definition for the c variable, it is implicitly initialized to 0 when this code block is first executed.

The result is then added by 1 and assigned to $NF. Here, NF is the number of fields in the line separated by the field separators. The default field separator (FS) is space. Note that space as FS is a special case in awk and multiple consecutive spaces will be considered as only one field separator.

Since NF is the number of fields, $NF refers to the last field. In this case, the assignment to $NF causes the 1 to be replaced by the value obtained by evaluating ((c++ % count) + 1).

The final 1 stands for true condition and the code block after it is omitted. The effect of this is an implicit print when the condition is true. Since 1 is always true, the action is always performed and the current line is printed, possibly after the transformation of the last block.

To better understand the process we can track the running of awk. awk has an implicit loop that loops over lines of the input.

  • 1st line: c is implicitly assigned 0. c++ is still 0 but it changes c to 1, (c++ % count) is 0 modulo 3 so is 0, ((c++ % count)+1) is 1, the assignment changes the last field (which also happens to be the last character in this case) to 1, and the final 1 prints this line, so we get DS: 1.

  • 2nd line: c is now 1. ((c++ % count)+1) is 2 and changes c to 2. The last field is changed to 2 and printed, so we get DS: 2.

  • 3rd line: Similarly, ((c++ % count)+1) changes c to 3 and evaluates to 3. We get DS: 3.

  • 4th line: Now here is when the % actually takes effect. (c++ %count) is 3 modulo 3 which equals 0, and ((c++%count)+1) evaluates to 1 again. We get DS: 1.

And so forth. This is how it works. Note that if there are any lines without the DS: they are printed verbatim.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.