Shell - Awk - reading from variable - shell

Is it possible to read for the awk input from variable (e.g. i) instead of file ?
awk 'something' temp
Can the 'temp' be replaced by the variable $i ? Really couldn't find it in man pages.

If your variable is a string, you can do that by using Bash here-string notation.
awk 'something' <<< "$temp"
For example:
$ temp='hello:world'
$ awk -F':' '{print $2}' <<< "$temp"
world
If you variable is a file, then just do
$ cat file
hello:world
$ f='./file'
$ awk -F':' '{print $1}' "$f"
hello

In a POSIX shell without here-string support, you can use a here-doc instead:
awk 'something' <<EOF
$i
EOF
awk 'something' <<< "$i" is just a shortcut for the above when the here document is very short or already contained in a variable.

Related

How to find values ​in quotes using bash?

I have a file with the following content:
"X-Apple-I-MD-M" = "MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s";
I want to extract the returned results Output as:
MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s
Tks Everybody!
One awk idea, assuming this is the only line in the file:
$ awk -F'"' '{print $4}' file
MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s
If there are other lines and you wish to focus only on the line with the string "X-Apple-I-MD-M":
Input file:
$ cat file
some line to ignore
"X-Apple-I-MD-M" = "MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s";
other line to ignore and "with" some "quotes"
New awk idea:
$ pattern='X-Apple-I-MD-M'
$ awk -v ptn="${pattern}" -F'"' '$2==ptn {print $4}' file
MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s
And saving the awk result in a variable:
$ mystring=$(awk ... )
$ echo "${mystring}"
MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s
NOTE: keep in mind if there are multiple matching lines in file then ${mystring} will contain a multi-line value (eg, line1match\nline2match\nline3match
I always like sed.
$: echo '"X-Apple-I-MD-M" = "MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s";'| sed -E 's/^.*= *"([^"]+)" *; *$/\1/'
MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s
if it's a file,
$: sed -E 's/^.*= *"([^"]+)" *; *$/\1/' file
MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s
With GNU grep(1), something like.
grep -Po '(?<="X-Apple-I-MD-M" = ").*(?=";)' <<< '"X-Apple-I-MD-M" = "MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s";'
If it is in a file.
grep -Po '(?<="X-Apple-I-MD-M" = ").*(?=";)' file.txt
If your content is consistent, an ugly solution is:
VAL='"X-Apple-I-MD-M" = "MR7v7ctwW0yr3mAUY3rAluXgOReA4CIn1JWJS2ba1s";'
echo $VAL
echo $VAL | awk '{split($0, a, " = "); print(substr(a[2], 2, length(a[2]) - 3))}'
Guessing by the bash tag, this is probably supposed to be in pure Bash, without external processes…? Two (somewhat) random options:
while IFS='"' read _ _ _ code _; do
echo "$code"
done
while read line; do
line="${line#\"*\" = \"}"
line="${line%\";}"
echo "$line"
done

Running awk command and print $1 with script that get arguments

I have my script (called test.sh) as follow:
#!/bin/bash
for i in "cat myfile | awk -F',' '{print $1}'"; do
.....
My problem is that my script receives arguments (./tesh.sh arg1 arg2) and '{print $1}' take the script argument (arg1) instead awk result, how can I solve it?
Your original problem is that you wrote the $1 between double-quotes.
"cat myfile | awk -F',' '{print $1}'"
bash variables are still substituted by their value if they are in a double-quoted string, disregarding the fact that they are between single-quotes inside the double-quotes. This is the reason why $1 is being replaced by arg1.
The second problem is that you want to execute the command:
cat myfile | awk -F',' '{print $1}'
but for this you need to use the notation $( command ) or `command`, the latter is however not advised as nesting is difficult.
So, your for-loop should read something like:
#!/usr/bin/env bash
for i in $(awk -F ',' '{print $1}' myfile); do
...
done

Writing an AWK instruction in a bash script

In a bash script, I need to do this:
cat<<EOF> ins.exe
grep 'pattern' file | awk '{print $2}' > results
EOF
The problem is that $2 is interpreted as a variable and the file ins.exe ends up containing
"grep 'pattern' file | awk '{print }' > results", without the $2.
I've tried using
echo "grep 'pattern' file | awk '{print $2}' > results" >> ins.exe
But it's the same problem.
How can I fix this?
Just escape the $:
cat<<EOF> ins.exe
awk '/pattern/ { print \$2 }' file > results
EOF
No need to pipe grep to awk, by the way.
With bash, you have another option as well, which is to use <<'EOF'. This means that no expansions will occur within the string.

Awk: Drop last record separator in one-liner

I have a simple command (part of a bash script) that I'm piping through awk but can't seem to suppress the final record separator without then piping to sed. (Yes, I have many choices and mine is sed.) Is there a simpler way without needing the last pipe?
dolls = $(egrep -o 'alpha|echo|november|sierra|victor|whiskey' /etc/passwd \
| uniq | awk '{IRS="\n"; ORS=","; print}'| sed s/,$//);
Without the sed, this produces output like echo,sierra,victor, and I'm just trying to drop the last comma.
You don't need awk, try:
egrep -o ....uniq|paste -d, -s
Here is another example:
kent$ echo "a
b
c"|paste -d, -s
a,b,c
Also I think your chained command could be simplified. awk could do all things in an one-liner.
Instead of egrep, uniq, awk, sed etc, all this can be done in one single awk command:
awk -F":" '!($1 in a){l=l $1 ","; a[$1]} END{sub(/,$/, "", l); print l}' /etc/password
Here is a small and quite straightforward one-liner in awk that suppresses the final record separator:
echo -e "alpha\necho\nnovember" | awk 'y {print s} {s=$0;y=1} END {ORS=""; print s}' ORS=","
Gives:
alpha,echo,november
So, your example becomes:
dolls = $(egrep -o 'alpha|echo|november|sierra|victor|whiskey' /etc/passwd | uniq | awk 'y {print s} {s=$0;y=1} END {ORS=""; print s}' ORS=",");
The benefit of using awk over paste or tr is that this also works with a multi-character ORS.
Since you tagged it bash here is one way of doing it:
#!/bin/bash
# Read the /etc/passwd file in to an array called names
while IFS=':' read -r name _; do
names+=("$name");
done < /etc/passwd
# Assign the content of the array to a variable
dolls=$( IFS=, ; echo "${names[*]}")
# Display the value of the variable
echo "$dolls"
echo "a
b
c" |
mawk 'NF-= _==$NF' FS='\n' OFS=, RS=
a,b,c

Passing bash input variables to awk

Trying to pass a variable into awk from user input:
Have tried variations of awk -v with errors stating 'awk: invalid -v option', even though the option is listed in man files.
#! /bin/bash
read -p "Enter ClassID:" CLASS
read -p "Enter FacultyName:" FACULTY
awk '/FacultyName/ {print}' data-new.csv > $FACULTY.csv
awk -vclass=${CLASS} '/class/ {print}' data-new.csv >> $FACULTY.csv
echo Class is $CLASS
echo Faculty member is $FACULTY
Some versions of awk require a space between the -v and the variable assignment. Also, you should put the bash variable in double-quotes to prevent unwanted parsing by the shell (e.g. word splitting, wildcard expansion) before it's passed to awk. Finally, in awk /.../ is a constant regular expression (i.e. /class/ will search for the string "class", not the value of the variable "class"). With all of this corrected, here's the awk command that I think will do what you want:
awk -v class="${CLASS}" '$0 ~ class {print}' data-new.csv >> $FACULTY.csv
Now, is there any reason you're using this instead of:
grep "$CLASS" data-new.csv >> $FACULTY.csv
Your script is not clear to me, but these all work:
CLASS=ec123
echo | awk -vclass=$CLASS '{print class}'
echo | awk -vclass=${CLASS} '{print class}'

Resources