6

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

8 Answers 8

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);}'
1
  • 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. Jan 16, 2017 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") }'
5
  • 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. Nov 21, 2010 at 16:10
  • @Gilles: Oops, I got in too big a hurry. Nov 21, 2010 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, 2012 at 11:07
  • @dubiousjim: Thanks, I've corrected my answer. Apr 19, 2012 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. Jan 16, 2017 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.

4
  • That won't work if the first field varies in length. Nov 21, 2010 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. Nov 21, 2010 at 16:11
  • @Gilles: I guess I just never use cut except for fixed width data. Nov 21, 2010 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, 2010 at 17:12
1
 % echo /var/sysconfig/network/my_functions  alpha beta gama | \
      awk -v word=alpha \
             '$2 == word { $1=""; print $0 }'
2
  • 2
    With the caveat already observerd by Dennis that this leaves the whitespace before $2. Nov 21, 2010 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)). Apr 19, 2012 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").

0

echo alpha beta gama | awk '{$1="";print}'

beta gama

1
  • 2
    Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Feb 15, 2023 at 16:37
-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
2
-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") }'
4
  • 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) Jan 16, 2017 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. Jan 16, 2017 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 !! Mar 25, 2017 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. Mar 25, 2017 at 10:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .