-1

Can you explain me how * works?

I have an input:

U         8649 275  Asia
Canada    3852 25   North America
China     3705 1032 Asia
USA       3615 237  North America
India     1267 746  -Asia
Mexico    762  78   -North America
France    211  55   Europe
Japan     144  120  Asia
England   94   56   Europe
cim 
B
BB

BBB

I tried a command

awk '/B*/' countries

And the output was:

U         8649 275  Asia
Canada    3852 25   North America
China     3705 1032 Asia
USA       3615 237  North America
India     1267 746  -Asia
Mexico    762  78   -North America
France    211  55   Europe
Japan     144  120  Asia
England   94   56   Europe
cim 
B
BB

BBB

I expected only the last four lines as an output. enter image description here

3

You missed the "null string" part in the description of *, which is present in every line.

In awk, to match one or more B's, use /B+/

  • Sorry, I do not understand, what I missed? – Lukáš Altman Feb 17 at 14:54
  • 1
    Maybe it's a wording issue; the "null" string is the empty string -- anything matches. – Jeff Schaller Feb 17 at 14:55
  • OK, when I change input to 'AAZkl' there is empty string too? Where? – Lukáš Altman Feb 17 at 15:02
  • 2
    The empty string is found between every character, and at the start and end of the string. – glenn jackman Feb 17 at 15:25
3

B* matches the empty string. There would be a match in-between each character on every line.

Here's an educational tool for you:

awk -v re='B+' '{ gsub(re, "(&)"); print }' file

This awk program would match the given expression and replace each match with whatever matched, but in parentheses. It's not perfect, but it serves most simple educational purposes.

The equivalent thing with sed would be, for some extended regular expression PATTERN,

sed -E 's/(PATTERN)/(&)/g' file

Running the awk command on your data with the expression B+:

$ awk -v re='B+' '{ gsub(re, "(&)"); print }' file
U         8649 275  Asia
Canada    3852 25   North America
China     3705 1032 Asia
USA       3615 237  North America
India     1267 746  -Asia
Mexico    762  78   -North America
France    211  55   Europe
Japan     144  120  Asia
England   94   56   Europe
cim
(B)
(BB)

(BBB)

As you can see, only three of the lines at the bottom of the file contains upper-case B, so only these are matched.

Another example, using just B:

$ awk -v re='B' '{ gsub(re, "(&)"); print }' file
U         8649 275  Asia
Canada    3852 25   North America
China     3705 1032 Asia
USA       3615 237  North America
India     1267 746  -Asia
Mexico    762  78   -North America
France    211  55   Europe
Japan     144  120  Asia
England   94   56   Europe
cim
(B)
(B)(B)

(B)(B)(B)

Here, each B is matched individually.

And finally, your actual expression in the question (my data is not properly tab-delimited), using B*:

$ awk -v re='B*' '{ gsub(re, "(&)"); print }' file
()U() () () () () () () () () ()8()6()4()9() ()2()7()5() () ()A()s()i()a()
()C()a()n()a()d()a() () () () ()3()8()5()2() ()2()5() () () ()N()o()r()t()h() ()A()m()e()r()i()c()a()
()C()h()i()n()a() () () () () ()3()7()0()5() ()1()0()3()2() ()A()s()i()a()
()U()S()A() () () () () () () ()3()6()1()5() ()2()3()7() () ()N()o()r()t()h() ()A()m()e()r()i()c()a()
()I()n()d()i()a() () () () () ()1()2()6()7() ()7()4()6() () ()-()A()s()i()a()
()M()e()x()i()c()o() () () () ()7()6()2() () ()7()8() () () ()-()N()o()r()t()h() ()A()m()e()r()i()c()a()
()F()r()a()n()c()e() () () () ()2()1()1() () ()5()5() () () ()E()u()r()o()p()e()
()J()a()p()a()n() () () () () ()1()4()4() () ()1()2()0() () ()A()s()i()a()
()E()n()g()l()a()n()d() () () ()9()4() () () ()5()6() () () ()E()u()r()o()p()e()
()c()i()m() ()
(B)
(BB)
()
(BBB)

This shows that B* matches in-between each character in the whole file, except for between the runs of multiple B characters towards the end.

We can also use this to show the difference between [A-Za-z-] and [A-Za-z-]+ (which you asked me about previously):

$ awk -v re='[A-Za-z-]' '{ gsub(re, "(&)"); print }' file
(U)         8649 275  (A)(s)(i)(a)
(C)(a)(n)(a)(d)(a)    3852 25   (N)(o)(r)(t)(h) (A)(m)(e)(r)(i)(c)(a)
(C)(h)(i)(n)(a)     3705 1032 (A)(s)(i)(a)
(U)(S)(A)       3615 237  (N)(o)(r)(t)(h) (A)(m)(e)(r)(i)(c)(a)
(I)(n)(d)(i)(a)     1267 746  (-)(A)(s)(i)(a)
(M)(e)(x)(i)(c)(o)    762  78   (-)(N)(o)(r)(t)(h) (A)(m)(e)(r)(i)(c)(a)
(F)(r)(a)(n)(c)(e)    211  55   (E)(u)(r)(o)(p)(e)
(J)(a)(p)(a)(n)     144  120  (A)(s)(i)(a)
(E)(n)(g)(l)(a)(n)(d)   94   56   (E)(u)(r)(o)(p)(e)
(c)(i)(m)
(B)
(B)(B)

(B)(B)(B)
$ awk -v re='[A-Za-z-]+' '{ gsub(re, "(&)"); print }' file
(U)         8649 275  (Asia)
(Canada)    3852 25   (North) (America)
(China)     3705 1032 (Asia)
(USA)       3615 237  (North) (America)
(India)     1267 746  (-Asia)
(Mexico)    762  78   (-North) (America)
(France)    211  55   (Europe)
(Japan)     144  120  (Asia)
(England)   94   56   (Europe)
(cim)
(B)
(BB)

(BBB)
  • Thank you very much, so null string is between two characters? – Lukáš Altman Feb 17 at 15:16
  • @LukášAltman Yes. A null string is an empty string, a string containing nothing. A match of the empty string is possible between every character. – Kusalananda Feb 17 at 15:17
  • Thus, when I write LL it means charakter L empty string and charakter L? – Lukáš Altman Feb 17 at 15:41
  • @LukášAltman For the purpose of matching a regular expression that could match an empty string, yes. – Kusalananda Feb 17 at 15:44

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.