5

I write the follwoing awk script:

% echo /var/sysconfig/network/my_functions  alpha beta gama  | \
      awk -v word=alpha '$2  == word { print $0 }'

how to tell awk that I want to print all line except $1 (/var/sysconfig/network/my_functions PATH ) so I will get the following:

alpha beta gama

instead of

/var/sysconfig/network/my_functions alpha beta gama

remark: line content can be anything and not limit by strings/word quantity

1

I think in awk there's no way but to remove the first field manually. (There are other ways if you're willing to normalize the inter-field space.)

awk '$2 == word {match($0, "("FS")+"); print substr($0, RSTART+RLENGTH);}'
  • Note that, if there is whitespace before $1, this solution will strip off that leading whitespace and leave all the fields (including $1). Not that there’s any suggestion in the question that that might happen. – Scott Jan 16 '17 at 4:43
6

If you set $1 to "" you will leave the delimiting space. If you don't want to do that you have to iterate over the fields:

awk '{for (f=2; f<=NF; ++f) { if (f!=2) {printf("%s",OFS);} printf("%s",$f)}; printf "\n" }'

Edit: fixed per Gilles' comment.

Another way to do the same thing:

awk '{d = ""; for (f=2; f<=NF; ++f) {printf("%s%s", d, $f); d = OFS}; printf("\n") }'
  • Errrm, this prints the fields on separate lines (after s/$NF/NF/). You can use if (f!=2) {printf("%s",OFS);} printf("%s",$f); as the loop body. – Gilles 'SO- stop being evil' Nov 21 '10 at 16:10
  • @Gilles: Oops, I got in too big a hurry. – Paused until further notice. Nov 21 '10 at 16:14
  • The second proposal needs to start by resetting d to ""; as written, it will only work as intended for the first line. – dubiousjim Apr 19 '12 at 11:07
  • @dubiousjim: Thanks, I've corrected my answer. – Paused until further notice. Apr 19 '12 at 11:16
  • Also, if there are multiple spaces (or tabs) between any of the fields (e.g., alpha  beta      gama), this will replace them with single spaces (alpha beta gama). Not that the OP expresses a requirement to preserve the inter-field whitespace. – Scott Jan 16 '17 at 4:43
2

Somehow I think this would be so much easier and more intuitive to do with the cut command:

echo /var/sysconfig/network/my_functions  alpha beta gama | cut -d' ' -f 2-

The only problem is that cut doesn't support multiple different types of whitespace at once for delimiters. So if you have spaces or tabs, it won't work.

  • That won't work if the first field varies in length. – Paused until further notice. Nov 21 '10 at 15:44
  • 2
    @Dennis: Yes, it will. It won't work if the first field delimiter varies in length (or uses a tab), as deltaray wrote. – Gilles 'SO- stop being evil' Nov 21 '10 at 16:11
  • @Gilles: I guess I just never use cut except for fixed width data. – Paused until further notice. Nov 21 '10 at 16:16
  • @Dennis, you're probably thinking of the -c option for cut, which is to cut based on the characters. -f is for fields. I wish cut was a bit more robust like awk is with separator length, because its quicker to use for things like this. – deltaray Nov 21 '10 at 17:12
1
 % echo /var/sysconfig/network/my_functions  alpha beta gama | \
      awk -v word=alpha \
             '$2 == word { $1=""; print $0 }'
  • 2
    With the caveat already observerd by Dennis that this leaves the whitespace before $2. – Gilles 'SO- stop being evil' Nov 21 '10 at 16:12
  • (Some necromancy here, but this thread popped up among the active questions just now): The extra whitespace can be trimmed with e.g. cut as in awk -v word=alpha '$2==word {$1=""; print}' | cut -b2- (if the poster doesn't want to use cut directly as in deltaray's answer, but that lacks the selection on "$2" part (which could be fixed with grep instead of awk)). – Daniel Andersson Apr 19 '12 at 11:55
1

This (somewhat complicated) solution, which is somewhat similar to Gilles’s answer,

  • outputs no space at the beginning of the line,
  • correctly handles the case where the input line begins with whitespace, and
  • preserves inter-field whitespace.
awk -v word=alpha '
    $2 == word {
        i = index($0, $1)               # Find $1 within $0 (the line).
        if (i > 0) {                    # Sanity check; should always be true.
                i = i + length($1)      # Find space after $1.
                temp = substr($0, i)
                i = index(temp, $2)     # Find $2 in remainder of line.
                if (i > 0) {            # Sanity check; should always be true.
                        print substr(temp, i)
                }
        }
    }'

I believe the in-line comments explain it fairly well.  We find $1’s position in the line (remember, I’m explicitly not assuming that it’s at the beginning).  Then, à la Gilles’s answer, we strip $1 (and the whitespace before it, if any) off the line.  Then find $2’s position in the remainder of the line, and strip off the whitespace before that.


Here is a slight streamlining of Dennis Williamson’s answer.

awk -v word=alpha '$2==word { for (f=2; f<=NF; ++f) printf("%s%s", $f, (f==NF?ORS:OFS)) }'

Like Dennis’s answer, it outputs the fields $2, $3, …, $NF (omitting $1) with default separation.  Dennis took the approaching of preceding $3, …, $NF (but not $2) with the default output field separator.  I took the approach of following $2, $3, …, $(NF-1) (but not $NF) with the OFS.  And, since $NF is followed by the output record separator (ORS), we can use a ?: operator with no null terms, and eliminate the final printf("\n").

-1

Everyone always makes it harder than it is

$ echo /var/sysconfig/network/my_functions alpha beta gama |
awk -v word=alpha '$2==word{print substr($0,index($0,$2))}'
alpha beta gama
-1

Use this if you want to change the delimiter. My delimiter is "|":

awk -F '|' '{d = ""; for (f=2; f<=NF; ++f) {printf("%s%s", d, $f); d = OFS}; printf("\n") }'
  • 1
    (1) This is a minor variation on Dennis Williamson’s answer.  If you copy somebody else’s answer, even to improve on it, you should give credit to the source.  (2) I believe that this doesn’t really contribute enough new information to justify a separate answer.  Things like this should probably be comments.  Once you have sufficient reputation you will be able to comment on any post.  … (Cont’d) – Scott Jan 16 '17 at 4:41
  • (Cont’d) …  I do realize you don’t have the reputation to do that, so earn it, and then do that. (3) Setting the field separator is often useful, but is not really relevant to this question.  In particular, your answer is incomplete since it doesn’t set the output field separator to match the input field separator, so your command will never produce the input line with the first field removed. – Scott Jan 16 '17 at 4:42
  • Thanks for correction, I am just learning shell scripting so I don't mind giving credit to Dennis :), anyways Thanks for correcting me - whoever is managing this can delete my post if this is redundant and of no help to others. Thanks and Good Luck !! – Dhaulakhandi Mar 25 '17 at 10:11
  • I appreciate everyone who is posting in stackover flow as this has helped many times throughout my career :), Thanks to the inventor and people who participate. – Dhaulakhandi Mar 25 '17 at 10:13

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.