7

I have a file Builder.java, with lines like:

public class Builder{
    @Override
    public void setCallId(long value) {
        set4ByteField(value, 48);
        setLogtype(1);
        setVerify("ABAB");
    }

    public void setOriginCallId(long value) {
        set8ByteField(value, 52);
    }

    public void setDateTimeYear(int value) {
        set2ByteField(value, 60);
    }
    
...

Then I want to replace only numbers > 50 to number+1, keeping all else as it was. Result:

public class Builder{
    @Override
    public void setCallId(long value) {
        set4ByteField(value, 48);
        setLogtype(1);
        setVerifyflag("ABAB");
    }

    public void setOriginCallId(long value) {
        set8ByteField(value, 53);
    }

    public void setDateTimeYear(int value) {
        set2ByteField(value, 61);
    }

    ....
}

I tried my best but wrote scripts which do not work, like:

cat Builder.java | awk -F'[,)]' '$2>50 {print $2+1}' > Builder.java
3
  • 1
    Should set51ByteField become set52ByteField if it exists in the input? If there are cases where numbers you do NOT want converted can appear in your real files then include some in the example in your question. It's always much easier to match the text you do want and much harder to not match the text that you don't want. – Ed Morton Feb 4 at 2:47
  • 1
    set51ByteField shouldn't be converted to set52ByteField. Thanks but I thought it's clear since i attached awk -F'[,)]' – masonshu Feb 4 at 9:04
  • No, showing an awk script that doesn't do what you want to do doesn't tell us everything you do want to do. That was obviously just 1 example of text that might end up getting changed undesirably, there are many more of course (and there may be text you want changed that the current answers don't change) - without a clear statement of the conditions under which you want changes to occur and similar ounter-examples in your sample input/output YMMV. – Ed Morton Feb 4 at 15:20
3

Your awk was almost right, but you want to alternate a field and then print the whole line. Also the output field separator is just removed and the missing comma and closing parentheses added manually:

awk 'BEGIN {FS="[,)]" ; OFS="" } /ByteField/ && $2 > 50 {$2=", "$2+1")"} ; 1' file

Where the 1 is always true, so always prints the line (for all lines) - note that it must be done after you altered the field. I added a match for /ByteField/ for more robustness.

For replacing the file: The redundant cat and piping to a command that has the same file as output will break. Use other approaches. E.g.

With GNU awk

awk -i inplace 'BEGIN ....' file

With sponge

awk 'BEGIN ...' file | sponge file

Or with help of a temporary file

awk 'BEGIN ...' file > file.alt
mv file.alt file
1
  • 1
    Readers should beware this should only be attempted in an input very similar to the one in the sample. I.e., if it is > 50, it will try to increment the first number between a , and ) and nothing more. More concretely, awk 'BEGIN{FS="[,)]"; OFS=""}$2>50{$2=", "$2+1")"};1' <<< 'sum(60,70,80)' returns sum(60, 71)80. Unfortunately the asker's example is far from ideal for not being complex enough. – Quasímodo Feb 3 at 16:19
8
  • Increment all numbers with absolute value greater than 50.

    perl -pe 's/\b(\d+)\b/$1>50 ? $1+1 : $1/ge' file
    

    The pattern is a sequence of digits (\d+) with boundaries (\b), so that it does not match the number 4 in set4ByteField, for example. The e flag at the end of the command allows the replacement to be treated as an expression, which is namely a ternary expresion on the captured group.

  • Increment all numbers greater than 50.

    perl -pe 's/(^|[^-])\b(\d+)\b/$1.($2>50 ? $2+1 : $2)/ge' file
    

    ^|[^-] matches the start of line or any character other than hyphen-minus to the left of the digits sequence. This rules out negative numbers.

By the way, you should not write to a file and read from it at the same time. Your attempt truncates the file before ever processing it, so you get an empty file. To edit the file in place, use Perl's -i flag (see the command-line options). Better still, -i.bak saves the original file with a .bak extension in case something goes wrong.

3
  • The asker asked explicitly about using awk to solve this. Perhaps you can convert your answer to one that uses awk instead of perl. – rlf Feb 3 at 21:07
  • 2
    Good answer. Tag added for perl users. – masonshu Feb 4 at 8:53
  • 3
    @rlf He did not. Perl is a Unix tool and can be a useful to other people with the same question. As you should know by now, here we don't only answer individuals—that would be consultancy—, but rather build a library of answers. I can't envisage any both general and non-tortuous Awk approach, even with GNU extensions, let alone without them. Perl, on the other hand, is clearly a right tool for the job, so rest assured that this answer will remain a Perl answer. – Quasímodo Feb 4 at 10:09

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.