You are using two languages: Bash and AWK.
Bash (which is your shell) and AWK are both programming languages, and they both allow you to store data in variables. But variables in your shell and variables in AWK are completely separate. Furthermore, variables in AWK no longer exist after your AWK script finishes. That is, once your awk
command is done running, your AWK variables are gone.
You can pass text of the form var=val
as a command-line argument to the awk
command. This assigns a variable in AWK. It does not affect shell variables in any way. When you use the -v
option (e.g., -v var=val
), that tells the awk
command to assign the variable before it runs your AWK script, but it is still an AWK variable, not a shell variable.
Your goal is to assign text from a specific column of a matched line to a shell variable. You can do that. But first, let's solve a simpler problem. This command finds rows that start with john
and displays the contents of the second column of each such row. If you have just one row that starts that way, it displays one item. If you have no such rows, it displays nothing, and if you have multiple rows that start with john
, then it will display multiple items on separate lines:
awk -F '|' '/^john/ { print $2 }' sample.txt
The AWK script in that command is /^john/ {print $2}
. I have enclosed it in single quotes ('
'
) so that it is treated as a single string, and not modified by the shell, before being passed to the awk
command. Otherwise the shell would interpret the AWK script as five separate words and operators for the shell itself (not AWK), which would lead to it taking just /^john/
as the AWK script. Everything after it would be treated as filenames to pass to awk
, which would not work. The shell would also expand $2
, and would perform word splitting and filename expansion (globbing) on the result (though enclosing $2
in double quotes as in your question would prevent splitting and globbing). You don't want any of those things to happen. In general, it is a good idea to enclose your AWK scripts in single quotes so they are passed faithfully to the awk
command.
With the sample.txt
file shown in your question, that command produces this output:
gold
silver
It prints text from two matching lines, rather than just one. Since you want just gold
, you probably don't really want to match all lines that start with john
. Instead, you probably want to match only lines where the entry in the first column is john
exactly. (One of the benefits of solving a simpler version of a problem first is that it can help you to refine your knowledge of precisely what problem you want to solve.) You can select only lines whose first column entry is exactly john
like this:
awk -F '|' '$1 == "john" { print $2 }' sample.txt
That displays:
gold
Now let's solve the full problem. Assigning to shell variables is not something that you can do in an AWK script. Not only is this not part of the AWK language, but the awk
command would have to be implemented as a part of your shell in order for it to be possible. This doesn't mean you can't do what you want to do--you absolutely can. It just means that, instead of attempting to write AWK code to assign to a shell variable, you must use the shell itself to do it.
You have an awk
command that displays the value you want assigned to a variable. So you can use command substitution in the shell to help you perform the assignment. This command assigns it to a shell variable called entry
(but you can use whatever name you like instead of entry
, such as column
):
entry="$(awk -F '|' '$1 == "john" { print $2 }' sample.txt)"
That works because the shell replaces $(
)
and everything inside it with the output produced by running the command inside it. That's command substitution. Note that, when you assign a shell variable like this, you must not have any spaces around the =
sign.
(By the way, you may notice that the text john
is colorized above as though it were not effectively quoted. That is actually a bug in the software that provides syntax highlighting on this website, which happens because it does not fully parse the contents of the outer "
"
, so it does not know that the inner "
"
is inside $(
)
. This is not a problem when you actually run the command, however.)
You can verify that gold
was assigned to the entry
shell variable by running:
echo "$entry"
That will display:
gold
For more information on variables in the AWK language, see this section 6.1.3 Variables in Gawk: Effective AWK Programming, which is the official documentation for GNU awk (gawk
). Although it documents GNU awk, it explains what is specific to GNU awk and what can also be used in other implementations of the AWK language. The awk
command in your Ubuntu system be either mawk
or gawk
, depending on what software you have installed and how you have configured it. One way to see which is to run awk -W version
.