Shell Scripting array not printing proper values - bash

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.

Related

How to grep first match and second match(ignore first match) with awk or sed or grep?

> root# ps -ef | grep [j]ava | awk '{print $2,$9}'
> 45134 -Dapex=APEC
> 45135 -Dapex=JAAA
> 45136 -Dapex=APEC
I need to put the first APEC of first as First PID, third line of APEC and Second PID and last one as Third PID.
I've tried awk but no expected result.
> First_PID =ps -ef | grep [j]ava | awk '{print $2,$9}'|awk '{if ($0 == "[^0-9]" || $1 == "APEC:") {print $0; exit;}}'
Expected result should look like this.
> First_PID=45134
> Second_PID=45136
> Third_PID=45135
With your shown samples and attempts please try following awk code. Written and tested in GNU awk.
ps -ef | grep [j]ava |
awk '
{
val=$2 OFS $9
match(val,/([0-9]+) -Dapex=APEC ([0-9]+) -Dapex=JAAA\s([0-9]+)/,arr)
print "First_PID="arr[1],"Second_PID=",arr[3],"Third_PID=",arr[2]
}
'
How about this:
$ input=("1 APEC" "2 JAAA" "3 APEC")
$ printf '%s\n' "${input[#]}" | grep APEC | sed -n '2p'
3 APEC
Explanation:
input=(...) - input data in an array, for testing
printf '%s\n' "${input[#]}" - print input array, one element per line
grep APEC - keep lines containing APEC only
sed -n - run sed without automatic print
sed -n '2p' - print only the second line
If you just want the APECs first...
ps -ef |
awk '/java[ ].* -Dapex=APEC/{print $2" "$9; next; }
/java[ ]/{non[NR]=$2" "$9}
END{ for (rec in non) print non[rec] }'
If possible, use an array instead of those ordinally named vars.
mapfile -t pids < <( ps -ef | awk '/java[ ].* -Dapex=APEC/{print $2; next; }
/java[ ]/{non[NR]=$2} END{ for (rec in non) print non[rec] }' )
After read from everyone idea,I end up with the very simple solution.
FIRST_PID=$(ps -ef | grep APEC | grep -v grep | awk '{print $2}'| sed -n '1p')
SECOND_PID=$(ps -ef | grep APEC | grep -v grep | awk '{print $2}'| sed -n '2p')
JAWS_PID=$(ps -ef | grep JAAA | grep -v grep | awk '{print $2}')

Filtered Windows comand works on it's own inside WSL, but not in a script

I have this command which returns an IP successfully:
user#laptop:~$ systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{print $2}'
172.22.0.1
I am trying to concatenate and export an environmental variable DISPLAY using a script with this content:
LOCAL_IP=$(systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{print $2}')
export DISPLAY=$LOCAL_IP:0
But after this script runs, DISPLAY doesn't look like expected:
user#laptop:~$ echo $DISPLAY
:02.22.0.1
I was expecting an answer 172.22.0.1:0. What went wrong?
LOCAL_IP appears to have a trailing \r; od -c <<< "${LOCAL_IP}" should show the value ending in a \r
One fix using parameter substitution:
$ export DISPLAY="${LOCAL_IP//$'\r'/}:0"
$ echo "${DISPLAY}"
172.22.0.1:0
Another option would be to add an additional pipe on the end of OP's current command, a couple ideas (dos2unix, tr -d '\r'); 3rd option modifies the awk script to remove the \r:
systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{print $2}' | dos2unix
# or
systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{print $2}' | tr -d '\r'
# or
systeminfo.exe | sed -n '/Connection Name: vEthernet (WSL)/,+4p' | egrep --word-regexp '\[01\]:' | awk '{gsub(/\r/,"");print $2}'
Another option would be to replace the sed/egrep/awk/tr with a single awk call. If OP wants to go this route I'd recommend asking a new question, making sure to provide the complete output from systeminfo.exe to better understand the parsing requirements.

How to print before and after dot text Unix

I am trying to print only specific output from sentence like below
Before and after dot text should be printed
InputVar="ABC SDFSG XYZ.AFGAJK JKK"
Expected output :
XYZ.AFGAJK
I am using cut command not working
echo "$InputVar" | cut -d'' -f2
Any other approach ?
Here are a few suggestions. awk with RS set to a space seems easiest. YMMV
$ echo "$InputVar" | cut -d ' ' -f 3
XYZ.AFGAJK
$ echo "$InputVar" | awk '/\./' RS=' '
XYZ.AFGAJK
$ echo "$InputVar" | awk '{for(i=1;i<=NF;i++) if(match($i,"\\.")) print $i}'
XYZ.AFGAJK
$ echo "$InputVar" | sed -n 's/.* \([^ .]*[.][^ .]*\) .*/\1/p'
XYZ.AFGAJK
Using cut:
If you really want to use cut, then you could try:
echo "$InputVar" | cut -d' ' -f3
Which uses a space character as a delimiter (you originally had an empty string, which is not allowed), and extracts field 3 rather than field 2.
Using grep:
You can use grep rather than cut, to match & extract specifically what you want:
echo "$InputVar" | grep -Eo '[^ ]+\.[^ ]+'
Explanation:
The -E option is for extended regex
The -o option is for extracting the matched component only
The regex matches a literal ., surrounded by a non-empty sequence of non-space characters
Comparing the two methods:
Either of these will work with your shown example. But, suppose the input string was instead:
InputVar="ABC SDFSG XYZ.AFGAJK JKK XYZ.ABC"
The version using grep would give all the matches (a literal . with non-space characters on either side).
Using cut however, you would need to specify the specific fields you want, i.e.
$ echo "$InputVar" | cut -d' ' -f3,5
XYZ.AFGAJK
XYZ.ABC
If you instead wanted just the n-th match, using the grep approach, you could use sed to select the n-th match, e.g.
$ echo "$InputVar" | grep -Eo '[^ ]+\.[^ ]+'
XYZ.AFGAJK
XYZ.ABC
$ echo "$InputVar" | grep -Eo '[^ ]+\.[^ ]+' | sed '1q;d'
XYZ.AFGAJK
$ echo "$InputVar" | grep -Eo '[^ ]+\.[^ ]+' | sed '2q;d'
XYZ.ABC

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}'

How to reference multiple string values in array in Shell script

I am trying to store multiple string in for loop but it giving me unwanted answer.
My code is :
#!/bin/bash
declare -a arr=("ps -ef | grep icsmpgum | grep $USER | grep -v grep | awk '{print $9,$8}' | awk '{print $1}'")
for i in "${arr[#]}"
do
echo "$i"
done
The output of
ps -ef | grep icsmpgum | grep $USER | grep -v grep | awk '{print $9,$8}' | awk '{print $1}'
is :
icsmpgum
ABC
DEF
I want to refer to these 3 string values in for loop but after applying for loop as mention above it giving me output as :
Output :
ps -ef | grep icsmpgum | grep tsaprm1 | grep -v grep | awk '{print ,}' | awk '{print }'
How should I store these string values in variables ?
You need to use a command substitution, rather than quoting the command:
arr=( $(ps -ef | grep icsmpgum | grep $USER | grep -v grep | awk '{print $9,$8}' | awk '{print $1}') )
I suspect that this will work but there's a lot of further tidying up to be done; all the filtering that you want to do is possible in one call to awk:
arr=( $(ps -ef | awk -v user="$USER" '!/awk/ && /icsmpgum/ && $0 ~ user { print $9 }') )
As mentioned in the comments, there are potential risks to building an array like this (e.g. glob characters such as * would be expanded and you would end up with extra values in the array). A safer option would be to use a process substitution:
read -ra arr < <(ps -ef | awk -v user="$USER" '!/awk/ && /icsmpgum/ && $0 ~ user { print $9 }')

Resources