b__
b__

Reputation: 21

Awk isn't taking bash variable

I found this command to work great:

awk -v "/mallory:/,/end-config/ {next} 1" /filename.txt

It takes everything in a file like this:

alice:
 config option 1
 config option 2
 end-config

mallory:          <--- Line gets deleted
 config option 1  <--- Line gets deleted
 config option 2  <--- Line gets deleted
 end-config       <--- Line gets deleted

bob:
 config option 1
 config option 2
 end-config

and only deletes the config block for mallory.

So now I wanted to define this in a bash script, so username could be a bash variable. I did this:

#!/bin/bash
username="mallory"
awk -v username="$username" "/username:/,/end-config/ {next} 1" /file.txt

Guess what. It doesn't remove anything. The output matches the file I started with. What gives? I imported my variable correctly, right?

Upvotes: 0

Views: 1323

Answers (5)

TrueY
TrueY

Reputation: 7610

/username:/ matches exactly the string You have written and nothing to do with the environment variable, but awk can read the environment variables. I would suggest:

username=mallory
awk '$0 == ENVIRON["username] ":",/end-config/ {next} 1' /file.txt

Actually this is not the nicest solution, as in the result there is double empty lines. So if username=mallory is set, then the result is:

alice:
 config option 1
 config option 2
 end-config


bob:
 config option 1
 config option 2
 end-config

But maybe it is ok for You.

Upvotes: 0

geekosaur
geekosaur

Reputation: 61467

"/username:/,/end-config/ {next}"

username will be literal there. To match against a variable, you have to use an explicit pattern match:

awk -v username="mallory" '
    $0 ~ (username ":"),/end-config/ {next}
    1'

Upvotes: 0

David W.
David W.

Reputation: 107090

The /foo/,/bar/ is the range of addresses where your {next} statement will work. And, addresses must be literals. Geekosaur's answer does work with a bit of tweaking:

awk -v username="mallory" '
    $0 ~ (username ":"),/end-config/ {next}
    1' filename.txt

The 1 is needed for awk to do anything. A better way may be:

awk -v username="mallory" '
    $0 ~ (username ":"),/end-config/ {next}
    {print $0}' filename.txt

Which states that your printing the line {print $0} if you don't skip it via the {next} statement. Awk prints the line if given no other commands and it returns a true (non-zero) value.

Upvotes: 1

clt60
clt60

Reputation: 63974

bit shorter with sed - save the following into file e.g. confdel.sh

sed "/^$1:/,/end-config/d"

and use it like:

bash confdel.sh mallory < config_file.txt

Upvotes: 0

Charlie Martin
Charlie Martin

Reputation: 112424

Alternatively, you could use

#!/bin/bash
username="mallory"
awk -v  "/${username}:/,/end-config/ {next} 1" /file.txt

Remember that the shell will do shell interpolation before the program gets to AWK, so ${username} will be replaced by mallory. To be more safe, you might want to use

#!/bin/bash
username="mallory"
awk -v '/'"${username}"':/,/end-config/ {next} 1' /file.txt

which will ensure that the awk program is protected from any other shell interpretation.

Upvotes: 1

Related Questions