Prev: building the printf format for a variable number of args
Next: changing the second + in a bash script
From: Hongyi Zhao on 29 Mar 2010 21:24 Hi all, In awk, we can substitute "foo" with "bar" ONLY for lines which contain "baz" using the following code: awk '/baz/{gsub(/foo/, "bar")}; 1' Now, I want to know how can I let the baz part get its value from a variable. I've tried the following code but failed: awk -v mybaz="baz" '/mybaz/{gsub(/foo/, "bar")}; 1' file BR. -- ..: Hongyi Zhao [ hongyi.zhao AT gmail.com ] Free as in Freedom :.
From: Thomas 'PointedEars' Lahn on 29 Mar 2010 23:36 Hongyi Zhao wrote: > In awk, we can substitute "foo" with "bar" ONLY for lines which > contain "baz" using the following code: > > awk '/baz/{gsub(/foo/, "bar")}; 1' > > Now, I want to know how can I let the baz part get its value from a > variable. I've tried the following code but failed: > > awk -v mybaz="baz" '/mybaz/{gsub(/foo/, "bar")}; 1' file You should state the implementation and version of awk you are using (awk, mawk, gawk, ...) $ echo foobar | awk 'BEGIN {x="/foo/"} $x {gsub("bar", "baz", $0)} 1' foobaz $ awk --version | head -n 1 GNU Awk 3.1.5 PointedEars
From: Ed Morton on 30 Mar 2010 00:01 On 3/29/2010 10:36 PM, Thomas 'PointedEars' Lahn wrote: > Hongyi Zhao wrote: > >> In awk, we can substitute "foo" with "bar" ONLY for lines which >> contain "baz" using the following code: >> >> awk '/baz/{gsub(/foo/, "bar")}; 1' >> >> Now, I want to know how can I let the baz part get its value from a >> variable. I've tried the following code but failed: >> >> awk -v mybaz="baz" '/mybaz/{gsub(/foo/, "bar")}; 1' file > > You should state the implementation and version of awk you are using (awk, > mawk, gawk, ...) > > $ echo foobar | awk 'BEGIN {x="/foo/"} $x {gsub("bar", "baz", $0)} 1' > foobaz > $ awk --version | head -n 1 > GNU Awk 3.1.5 > > > PointedEars No, that only APPEARS to work because x contains a non-integer string so $x becomes the value of $0 which is "foobar" which is non-NULL and so a true condition. Look: $ echo foobar | awk 'BEGIN {x="/foo/"} $x {gsub("bar", "baz", $0)} 1' foobaz $ echo foobar | awk 'BEGIN {x="/rabbit/"} $x {gsub("bar", "baz", $0)} 1' foobaz $ echo foobar | awk 'BEGIN {x="whatever"} $x {gsub("bar", "baz", $0)} 1' foobaz $ echo foobar | awk 'BEGIN {x="2"} $x {gsub("bar", "baz", $0)} 1' foobar That last one didn't produce a true condition as x is 2 so $x is $2 which evaluates to a NULL string as there's just one field of input. The right way to do that is: $ echo foobar | awk 'BEGIN{x="foo"} $0 ~ x{gsub("bar", "baz", $0)} 1' foobaz so for the OP the solution to the question you posted would be: awk -v mybaz="baz" '$0 ~ mybaz{gsub(/foo/, "bar")} 1' file Regards, Ed.
From: Thomas 'PointedEars' Lahn on 30 Mar 2010 06:32 Ed Morton wrote: > Thomas 'PointedEars' Lahn wrote: >> Hongyi Zhao wrote: >>> In awk, we can substitute "foo" with "bar" ONLY for lines which >>> contain "baz" using the following code: >>> >>> awk '/baz/{gsub(/foo/, "bar")}; 1' >>> >>> Now, I want to know how can I let the baz part get its value from a >>> variable. I've tried the following code but failed: >>> >>> awk -v mybaz="baz" '/mybaz/{gsub(/foo/, "bar")}; 1' file >> >> You should state the implementation and version of awk you are using >> (awk, mawk, gawk, ...) >> >> $ echo foobar | awk 'BEGIN {x="/foo/"} $x {gsub("bar", "baz", $0)} 1' >> foobaz >> $ awk --version | head -n 1 >> GNU Awk 3.1.5 >> [...] > > No, that only APPEARS to work because x contains a non-integer string so > $x becomes the value of $0 which is "foobar" which is non-NULL and so a > true condition. Look: > [...] Thank you, it turned out to be too simple to be true. I had read | ~ !~ Regular expression match, negated match. NOTE: Do not use | a constant regular expression (/foo/) on the left-hand side | of a ~ or !~. Only use one on the right-hand side. The | expression /foo/ ~ exp has the same meaning as (($0 ~ | /foo/) ~ exp). This is usually not what was intended. but did not expect the `x' in a standalone `$x' to be expanded. Probably I'm spoiled by (ba)sh ;-) > The right way to do that is: > > $ echo foobar | awk 'BEGIN{x="foo"} $0 ~ x{gsub("bar", "baz", $0)} 1' > foobaz > > so for the OP the solution to the question you posted would be: > > awk -v mybaz="baz" '$0 ~ mybaz{gsub(/foo/, "bar")} 1' file ACK. I am still a bit puzzled about the trailing `1', though. Is it the equivalent of a true-value relational expression with a missing action equivalent to `{print}' as described in section "PATTERNS AND ACTIONS" of the (gawk) manpage? I used to use `{print}' explicitly instead: awk -v mybaz="baz" '$0 ~ mybaz {gsub(/foo/, "bar")} {print}' file Also, is there an advantage to use -v over a BEGIN block when there is no BEGIN block to refer to the variable? Is there another disadvantage, e.g. reduced compatibility? TIA. PointedEars
From: Ed Morton on 30 Mar 2010 07:58 On 3/30/2010 5:32 AM, Thomas 'PointedEars' Lahn wrote: > Ed Morton wrote: > >> Thomas 'PointedEars' Lahn wrote: >>> Hongyi Zhao wrote: >>>> In awk, we can substitute "foo" with "bar" ONLY for lines which >>>> contain "baz" using the following code: >>>> >>>> awk '/baz/{gsub(/foo/, "bar")}; 1' >>>> >>>> Now, I want to know how can I let the baz part get its value from a >>>> variable. I've tried the following code but failed: >>>> >>>> awk -v mybaz="baz" '/mybaz/{gsub(/foo/, "bar")}; 1' file >>> >>> You should state the implementation and version of awk you are using >>> (awk, mawk, gawk, ...) >>> >>> $ echo foobar | awk 'BEGIN {x="/foo/"} $x {gsub("bar", "baz", $0)} 1' >>> foobaz >>> $ awk --version | head -n 1 >>> GNU Awk 3.1.5 >>> [...] >> >> No, that only APPEARS to work because x contains a non-integer string so >> $x becomes the value of $0 which is "foobar" which is non-NULL and so a >> true condition. Look: >> [...] > > Thank you, it turned out to be too simple to be true. I had read > > | ~ !~ Regular expression match, negated match. NOTE: Do not use > | a constant regular expression (/foo/) on the left-hand side > | of a ~ or !~. Only use one on the right-hand side. The > | expression /foo/ ~ exp has the same meaning as (($0 ~ > | /foo/) ~ exp). This is usually not what was intended. > > but did not expect the `x' in a standalone `$x' to be expanded. Probably > I'm spoiled by (ba)sh ;-) Since you don't use "$" to dereference the value of awk variables (other than $1, $2, etc.) then doing x=2 printf "%s\n",x printf "%s\n",$x in awk is equivalent to: x=2 printf "%s\n" "$x" eval printf '"%s\n"' \"\${$x}\" in shell IF the value of x is a number. If the value of x is not a number then in awk $x is the same as $0. > >> The right way to do that is: >> >> $ echo foobar | awk 'BEGIN{x="foo"} $0 ~ x{gsub("bar", "baz", $0)} 1' >> foobaz >> >> so for the OP the solution to the question you posted would be: >> >> awk -v mybaz="baz" '$0 ~ mybaz{gsub(/foo/, "bar")} 1' file > > ACK. I am still a bit puzzled about the trailing `1', though. Is it the > equivalent of a true-value relational expression with a missing action > equivalent to `{print}' as described in section "PATTERNS AND ACTIONS" of > the (gawk) manpage? Yes. These are all equivalent: awk '1' awk '1==1' awk '"foo"' awk '{print}' awk '{print $0}' awk '1==1{print $0}' I used to use `{print}' explicitly instead: > > awk -v mybaz="baz" '$0 ~ mybaz {gsub(/foo/, "bar")} {print}' file > > Also, is there an advantage to use -v over a BEGIN block when there is no > BEGIN block to refer to the variable? Only that if you in future had to set the awk variable based on a shell variable then you can easily change this: awk -v awkvar="foo" '...' to: shellvar="foo" awk -v awkvar="$shellvar" ....' Is there another disadvantage, e.g. > reduced compatibility? No. The only incompatible awk would be old, broken awk (/usr/bin/awk on Solaris) but no-one should use that for many other reasons anyway so using "-v" is a decent test to make sure that's not the awk you're picking up. Ed. > > TIA. > > > PointedEars
|
Next
|
Last
Pages: 1 2 Prev: building the printf format for a variable number of args Next: changing the second + in a bash script |