Grep variable pattern match - linux

How can I get this to work?
#!/bin/bash
SOMETHING=$(egrep '^ something' /some/dir/file.conf | awk -F '.' '{print $1}' | awk '{print $2}')
if [ $SOMETHING = 123 ]; then
echo "Found 123"
else
echo "Cannot find 123" && exit 1
fi
Results in grep complaining about a syntax error. It doesn't like the '^ something'

Your multiple commands with pipes can be simply replaced with the awk itself. Use following script:
SOMETHING=$(awk '/^ something/{print substr($4, 1, 3);}' somefile.conf)
if [ "$SOMETHING" = "123" ]; then
echo "Found 123"
else
echo "Cannot find 123" && exit 1
fi
EDIT: Looks like you've edited the question and your script after I posted my anser. Here is the modified awk command for you latest edit (don't do it again pls):
SOMETHING=$(awk -F "." '/^ something/{split($1, a, " "); print a[2]}' somefile.conf)

Related

How to extract lines containing blank in a specific column with Linux command

Example:
aa\tab\tac\tad\tae
ba\tbb\tbc
ca\tcb\tcc
da\tdb\tdc\tdd
Expected output:
ba\tbb\tbc
ca\tcb\tcc
I want to extract lines containing blank in a 4th column with linux command. If you know the command, could you let me know it?
Using awk
$ awk -F"\\" '{if($4=="") print}' input_file
ba\tbb\tbc
ca\tcb\tcc
You can use cut and use "" as delimiter and check the field 4 if it is not empty. Then use the grep -v to check if a trailing "" exists or not.
in an If statement you can get the result.
text='aa\tab\tac\'
if [[ -z $(echo $text | cut -d \\ -f 4 | grep -v \\\\\$) ]]; then
if[[ -z $(echo $text | grep -v \\\\\$) ]]; then
echo $text
else
echo 'Text has a slash at the end'
fi
else
echo 'Not valid input'
fi

Increment variable when matched awk from tail

I'm monitoring from an actively written to file:
My current solution is:
ws_trans=0
sc_trans=0
tail -F /var/log/file.log | \
while read LINE
echo $LINE | grep -q -e "enterpriseID:"
if [ $? = 0 ]
then
((ws_trans++))
fi
echo $LINE | grep -q -e "sc_ID:"
if [ $? = 0 ]
then
((sc_trans++))
fi
printf "\r WSTRANS: $ws_trans \t\t SCTRANS: $sc_trans"
done
However when attempting to do this with AWK I don't get the output - the $ws_trans and $sc_trans remains 0
ws_trans=0
sc_trans=0
tail -F /var/log/file.log | \
while read LINE
echo $LINE | awk '/enterpriseID:/ {++ws_trans} END {print | ws_trans}'
echo $LINE | awk '/sc_ID:/ {++sc_trans} END {print | sc_trans}'
printf "\r WSTRANS: $ws_trans \t\t SCTRANS: $sc_trans"
done
Attempting to do this to reduce load. I understand that AWK doesn't deal with bash variables, and it can get quite confusing, but the only reference I found is a non tail application of AWK.
How can I assign the AWK Variable to the bash ws_trans and sc_trans? Is there a better solution? (There are other search terms being monitored.)
You need to pass the variables using the option -v, for example:
$ var=0
$ printf %d\\n {1..10} | awk -v awk_var=${var} '{++awk_var} {print awk_var}'
To set the variable "back" you could use declare, for example:
$ declare $(printf %d\\n {1..10} | awk -v awk_var=${var} '{++awk_var} END {print "var=" awk_var}')
$ echo $var
$ 10
Your script could be rewritten like this:
ws_trans=0
sc_trans=0
tail -F /var/log/system.log |
while read LINE
do
declare $(echo $LINE | awk -v ws=${ws_trans} '/enterpriseID:/ {++ws} END {print "ws_trans="ws}')
declare $(echo $LINE | awk -v sc=${sc_trans} '/sc_ID:/ {++sc} END {print "sc_trans="sc}')
printf "\r WSTRANS: $ws_trans \t\t SCTRANS: $sc_trans"
done

Hex compare in bash scripting

I am facing some issue when I am reading the 3rd word(a hex string) of each line in a text file and compare it with a hex number. Can some one please help me on it.
#!/bin/bash
A=$1
cat $A | while read a; do
a1=$(echo \""$a"\" | awk '{ print $3 }')
#echo $a > cut -d " " -f 3
echo $a1
(("$a1" == 0x10F7))
echo $?
done
But when I use below, the comparison happens correctly,
a1= 0xADCAFE
(( "$a1" == 0x10F7 ))
echo $?
Then why it is showing issue when I read like below,
a1=$(echo \""$a"\" | awk '{ print $3 }')
or> a1=$(echo $a | awk '{ print $3 }')
echo $a prints intended hex value, but comparison does not happen.
Regards,
Running Awk inside a while read loop is an antipattern. Just do the loop in Awk; it's good at that.
awk '$3 == 4343' "$1"
If you want to compare against a string whose value is "0x10F7" then it's
awk '$3 == "0x10F7"' "$1"
If you want to match either, case insensitively etc, a regex is a good way to do that.
awk '$3 ~ /^(0x10[Ff]7|4343)$/' "$1"
Notice how the $1 in double quotes is handled by the shell, and gets replaced by a (properly quoted!) copy of the script's first command-line argument before Awk runs, while the Awk script in single quotes has its own namespace, so $3 is an Awk variable which refers to the third field in the current input line.
Either way, avoid the useless use of cat and always always always quote variables which contain file names with double quotes.
That's literal double quotes. You seem to have tried both a dangerous bare $a and a doubly double-quoted "\"$a\"" where the simple "$a" would be what you actually want.
Thank you all for your responses, Now my script is working fine. I was trying to match two files, below script does the purpose
#!/bin/bash
A=$1
B=$2
dos2unix -f "$A"
dos2unix -f "$B"
rm search_match.txt search_data_match.txt search_nomatch.txt search_data_nomatch.txt
while read line;do
search_word=$(echo $line | awk '{ print $1 }')
grep "$search_word" $B >> temp_file.txt
while read var;do
file1_hex=$(echo $line | awk '{ print $2 }')
file2_hex=$(echo $var | awk '{ print $3 }')
(("$file1_hex" == "$file2_hex"))
zero=$(echo $?)
if [ "$zero" -eq 0 ] ; then
echo $line >> search_match.txt
echo $var >> search_data_match.txt
else
echo $line >> search_nomatch.txt
echo $var >> search_data_nomatch.txt
fi
done < "temp_file.txt"
rm temp_file.txt
done < "$A"

in Shell, How to insert a substring if not found in string

I want changes_summary to always be in format <x> files changed, <y> insertion(+), <z> deletions(-) where <x> <y> and <z> are some numbers, but diffstat misses insertions and/or deletions part if <y> and/or <z> is zero, I tried to make it print as <x> files changed 0 insertion(+), 0 deletions(-) always, is there a better or easy way to do this? I would like to change $changes_summary variable so I can use it later part of the script.
changes_summary=`diff -ur ./dir1 ./dir2 | diffstat | tail -1`
if ! echo $changes_summary | grep -q "insertions" && ! echo $changes_summary | grep -q "deletions" ; then
echo $changes_summary | awk '{print $1 " " $2 " " $3 " " "0 insertion(+)," " " "0 deletions(-)"}'
elif ! echo $changes_summary | grep -q "insertions" && echo $changes_summary | grep -q "deletions" ; then
echo $changes_summary | awk '{print $1 " " $2 " " $3 " " "0 insertion(+), "$4 " " $5 }'
elif echo $changes_summary | grep -q "insertions" && ! echo $changes_summary | grep -q "deletions" ; then
echo $changes_summary | awk '{print $1 " " $2 " " $3 " " $4 " " $5 "0 deletions(-)" }'
fi
Probably the closest you can get without some serious bash magic or an other language is something like the following.
changes_summary=`diff -ur ./dir1 ./dir2 | diffstat -s`
CC=$(echo "$changes_summary" | sed -n 's:\(.*[0-9]\+ .* changed\).*:\1:p')
II=$(echo "$changes_summary" | sed -n 's:.*\([0-9]\+ insertions\?\).*:\1:p')
DD=$(echo "$changes_summary" | sed -n 's:.*\([0-9]\+ deletions\?\).*:\1:p')
echo "${CC}, ${II:-0 insertions}(+), ${DD:-0 deletions}(-)"
Sed strips out the message corresponding to each stat. The -n suppresses the normal output, p prints only if a match is found. If not, then CC, II, DD will be empty, in which case the ${II:-...} pattern substitutes a default value.
From man bash:
${parameter:-word} Use Default Values. If parameter is unset or null,
the expansion of word is substituted. Otherwise, the value of
parameter is substituted.
Note that keeping the (s) with s\? might be an overkill for you.
The other option is that in bash you can check for containment with [[ $a =~ "b" ]] and use your original approach. It spares you the greps at least and "b" here can also be regex if you drop the quotes.
if ! [[ "$changes_summary" =~ "insert" ]]; then
awk ...
fi
You can also find the =~ in man bash.

bash error: 2: integer expression expected

I have a problem with a simple bash script..
#!/bin/bash
libc_main_ver=$(dpkg -l |grep libc6 |awk '{print$3}' |awk -F .
'{print$1}'|xargs -n 1)
if [ "$libc_main_ver" -eq 2 ] ;then
echo ok
else
echo nope
fi
exit 0
When i try execute the script it gives me the error:
2: integer expression expected
What's the problem?
dpkg -l |grep libc6 |awk '{print$3}' |awk -F . '{print$1}'|xargs -n 1
This prints only 2 not other values.
Some suggestions?
Insert
echo "<$libc_main_ver>"
after the first line and the error will be obvious. Very likely there's a space or newline in there somewhere which you shouldn't numerically compare with 2.
Very esoteric: the problem could be the literal in -eq 2 as well. If it is followed by a carriage return character, I can somewhat reproduce your error message:
$ test "2" -eq 2^R
bash: test: 2: integer expression expected
where ^R is a literal carriage return entered with CTRL-V CTRL-R. To verify or exclude this, run od -bc nameofyourscript
What if you tried this:
#!/bin/bash
libc_main_vers=$(dpkg -l | grep libc6 | awk '{ print $3 }' | awk -F . '{ print $1 }')
for ver in ${libc_main_vers}; do
if (( ver == 2 )); then
echo ok
else
echo nope
fi
done
exit 0
Here is another version:
#!/bin/bash
libc_full=$(dpkg -l | grep libc6 | head -n 1 | awk '{ print $3 }')
libc_main=$(echo ${libc_full} | grep -o "^[0-9]*")
libc_update=$(echo ${libc_full} | grep -o "[0-9]*$")
if (( libc_main == 2 )); then
echo "Main version is OK"
if (( libc_update >= 7 )); then
echo "Update version is OK"
exit 0
fi
fi
exit 1
It's unclear whether you require all the packages you list to have a major version number 2, or are just verifying that at least one of them does.
Anyway, if we start with the observation that grep foo | awk { print $1 } can usually be refactored into a single Awk script awk '/foo/ { print $1 }' we can already simplify your script; but it sometimes makes sense to refactor basically all of it into Awk. Perhaps like this:
dpkg -l 'libc6*' | awk '$3 !~ /^2\./ { exit 1 }' && echo ok || echo nope
If you are satisfied with just one package meeting the condition, change to something like
dpkg -l 'libc6*' | awk '$3 ~ /^2\./ { exit 0 } END { exit 1 }' && echo ok || echo nope
As always, foo && success || failure is a shorthand for
if foo; then
success
else
failure
fi
where the longhand probably makes sense if your real script needs to do something moderately more complex than just echo a value.
Do note that the output from dpkg -l is not necessarily suitable for scripts. Maybe use dpkg-query -f '${Version}\n' -W 'libc6' instead for robustness.

Resources