How to prevent bash for loop to transform string data - bash

I want to filter out datestamps from the message log and delete all occurances:
(basicly this is a part of an usb history cleaner script, head -n1 added only becouse of testing)
delimiter=`echo $HOSTNAME | cut -f1 -d.`
for item in `egrep usb /var/log/messages | awk -F"$delimiter" '{print $1}' | uniq | head -n1`; do
echo ${item}
done
when I run this command:
egrep usb /var/log/messages | awk -F"$delimiter" '{print $1}' | uniq | head -n1
the output is fine:
Mar 31 03:25:03
but when it will be given back to the for loop, the data transfers like this becouse of the spaces:
Mar
31
03:25:03
the question is: how can I prevent this kind of behaviour?

Instead of:
for item in `whatever`; do
echo ${item}
done
use:
whatever |
while IFS= read -r item; do
echo "${item}"
done
but your whole script could be re-written as just:
awk -F"${HOSTNAME%%.*}" '/usb/ && !seen[$1]++ {print $1}' /var/log/messages

Related

Shell Scripting array not printing proper values

I have this simple Shell Script where I am searching for ID and Port Number from the file and saving it in Array. However When I try to print them I am not getting expected results. I am looping the array to print the 1st and 2nd element and then increasing by two to print 3rd and 4th element. I also want to print them like each ID Port in separate line, like this:
ID Port
ID Port
My code is:
myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); for ((i=0;i<"${#myarr[#]}";i+=2)) ; do echo $i; printf "%s\n" "${myarr[$i]}" "${myarr[$i+1]}" ; done;
Even If I try to echo the whole array I only see the last element, whereas I could print each individual element without an issue.
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[#]}
45210
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[0]}
19
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[1]}
45210
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[2]}
20
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[3]}
45210
From the output you give, I suspect that the problem is due to carriage return characters in the radius-req file. My guess is the file is from Windows (or maybe a web download), which uses carriage return + linefeed as a line terminator. Unix uses just linefeed (aka newline) as a terminator, and unix programs will treat the carriage return as part of the content of the line. Net result: you get things like "19<CR>" and "45210<CR>" as array values, and when you print them it prints them all over top of each other.
If I'm right about the problem, it's pretty easy to fix. Just replace less radius-req (which you shouldn't use anyway, see William Pursell's comment) with tr -d '\r' <radius-req. The tr command does character replacements, -d means just delete instead of replacing, and \r is its notation for the carriage return character. Result: it deletes the carriage returns before they have a chance to mess things up.

grep search with filename as parameter

I'm working on a shell script.
OUT=$1
here, the OUT variable is my filename.
I'm using grep search as follows:
l=`grep "$pattern " -A 15 $OUT | grep -w $i | awk '{print $8}'|tail -1 | tr '\n' ','`
The issue is that the filename parameter I must pass is test.log.However, I have the folder structure :
test.log
test.log.001
test.log.002
I would ideally like to pass the filename as test.log and would like it to search it in all log files.I know the usual way to do is by using test.log.* in command line, but I'm facing difficulty replicating the same in shell script.
My efforts:
var-$'.*'
l=`grep "$pattern " -A 15 $OUT$var | grep -w $i | awk '{print $8}'|tail -1 | tr '\n' ','`
However, I did not get the desired result.
Hopefully this will get you closer:
#!/bin/bash
for f in "${1}*"; do
grep "$pattern" -A15 "$f"
done | grep -w $i | awk 'END{print $8}'

Hide output of cat command

I have this line of code which I would like to hide its output.
Vrs=$(cat $(echo $line | awk -F"-" '{print "/var/AS-"$2"-"toupper($3)"-"$4}') | grep "YES" | cut -d":" -f5)
I have tried to include &> /dev/null at the end of the line but it doesn't work.
Does anyone know how to do this?
I am not exactly sure what you are trying to achieve, but your cat call looks redundant to me.
Vrs=$(echo "$line" | awk -F"-" '{print "/var/AS-"$2"-"toupper($3)"-"$4}' | grep "YES" | cut -d":" -f5)
You could rephrase the statement to
Vrs=$(echo "$line" | awk -F"-" '{print "/var/AS-"$2"-"toupper($3)"-"$4}' | grep "YES" | cut -d":" -f5)
This does the same thing. In the command is successful, you would get the result stored in Vrs. No output would be shown in the stdout. However, if you expect errors, you could do :
Vrs=$(echo "$line" | awk -F"-" '{print "/var/AS-"$2"-"toupper($3)"-"$4}' | grep "YES" | cut -d":" -f5 2>/dev/null)
This will suppress the errors and give you an empty $Vrs
Notes:
I have double quoted $line to prevent globbing and word splitting.

getting a part of the output from a sed command

I have this Command :
cat -n file.log | grep "Start new test" | tail -1 | cut -f 1 | xargs -I % sed -n %',$s/is not alive/&/p' file.log
That gives the output of the whole line :
Jan 19 23:20:33 s_localhost#file platMgt.xbin[3260]: blade 10 is not alive
Jan 19 23:20:33 s_localhost#file platMgt.xbin[3260]: blade 11 is not alive
how can I modify it to get the last part only :
blade 11 is not alive
can I modify that in a way to display :
Error:blade 11 is not alive ?
Thank you for your response
You can use cut to delimit it on the colons and then add the error message:
cat -n file.log | grep "Start new test" | tail -1 | cut -f 1 | xargs -I % sed -n %',$s/is not alive/&/p' file.log | cut -d: -f 4 | xargs -I % echo Error: %
To get the last part after colon awk is better tool:
s='Jan 19 23:20:33 s_localhost#file platMgt.xbin[3260]: blade 10 is not alive'
awk -F':' '{print "Error:" $NF}' <<< "$s"
OUTPUT:
blade 10 is not alive
EDIT: WIth your piped commands you can combine it as:
grep "Start new test" file.log|tail -1|awk -F':' '{print "Error:" $NF}'
PS: Though this whole thing is possible in awk itself.
The following obtains the the last ":" separated field with a sed command,
cat text.txt | sed 's/^.*: \([^:]*$\)/\1/g'

Print out onto same line with ":" separating variables

I have the following piece of code and would like to display HOST and RESULT side by side with a : separating them.
HOST=`grep pers results.txt | cut -d':' -f2 | awk '{print $1}'`
RESULT=`grep cleanup results.txt | cut -d':' -f2 | awk '{print $1}' | sed -e 's/K/000/' -'s/M/000000/'`
echo ${HOST}${RESULT}
Please can anyone assist with the final command to display these, I am just getting all of hosts and then all of results.
You probably want this:
HOST=( `grep pers results.txt | cut -d':' -f2 | awk '{ print $1 }'` ) #keep the output of the command in an array
RESULT=( `grep cleanup results.txt | cut -d':' -f2 | awk '{ print $1 }' | sed -e 's/K/000/' -'s/M/000000/'` )
for i in "${!HOST[#]}"; do
echo "${HOST[$i]}:${RESULT[$i]}"
done
A version that works without arrays, using an extra file handle to read from 2 sources at at time.
while read host; read result <&3; do
echo "$host:$result"
done < <( grep peers results.txt | cut -d: -f2 | awk '{print $1}' ) \
3< <( grep cleanup results.txt | cut -d':' -f2 | awk '{print $1}' | sed -e 's/K/000/' -'s/M/000000/')
It's still not quite POSIX, as it requires process substitution. You could instead use explicit fifes. (Also, an attempt to shorten the pipelines that produce the hosts and results. It's probably possible to combine this into a single awk command, since you can either do the substitution in awk, or pipe to sed from within awk. But this is all off-topic, so I leave it as an exercise to the reader.)
mkfifo hostsrc
mkfifo resultsrc
awk -F: '/peers/ {split($2, a, ' '); print a[1]}' results.txt > hostsrc &
awk -F: '/cleanup/ {split($2, a, ' '); print a[1]}' results.txt | sed -e 's/K/000' -e 's/M/000000/' > resultsrc &
while read host; read result <&3; do
echo "$host:$result"
done < hostsrc 3< resultsrc

Resources