getting a column of a specific line in bash - bash

I have this command :
id=$(xl list|egrep $Name| tr -s ' ' | cut -d ' ' -f 2)
which xl list output something like this:
Name ID Mem VCPUs State Time(s)
Domain-0 0 5923 8 r----- 4266.0
new_redhat9-clone 3 1027 1 r----- 1019.6
new_redhat9 4 1027 1 -b---- 40.1
Actually I want to get the ID of a given Name. This works when Name=new_redhat9-clone (it returns 3) but doesnt work when Name=new_redhat9 (it returns: 3 4!!!!).
what is wrong?!!!

grep searches the string pattern match. egrep new_redhat9 match with "new_redhat9" and "new_redhat9-clone". Try add whiteespace (or \t) after pattern, rewrite like this
id=$(xl list|egrep 'new_redhat9 '| tr -s ' ' | cut -d ' ' -f 2)

You could use awk instead of egrep,tr and cut commands,
id=$(xl list | awk '$1=="new_redhat9" {print $2}')
Awk command searches for the exact string new_redhat9 in the first column of xl list output . If it finds any then then value of column2 on the corresponding record is stored to the variable id.
You could check the output through echo $id command.
If the name is stored in a variable, then give a try to the below command
id=$(xl list | awk -v var=$Name '$1==var {print $2}')

Related

Need to grep a specific string using curl

I am trying to get language code from pages by curl
I wrote below and work...
curl -Ls yahoo.com | grep "lang=" | head -1 | cut -d ' ' -f 3 | cut -d"\"" -f 2
but sometimes code is different like
curl -Ls stick-it.app | grep "lang=" | head -1 | cut -d ' ' -f 3 | cut -d"\"" -f 2
they wrote like
<html dir="rtl" lang="he-IL">
I just need to get he-IL
If is there any other way, I would appreciate it...
Using any sed in any shell on every Unix box:
$ curl -Ls yahoo.com | sed -n 's/^<html.* lang="\([^"]*\).*/\1/p'
en-US
If you have gnu-grep then using -P (perl regex):
curl -Ls yahoo.com | grep -oP '\slang="\K[^"]+'
he-IL
With awk's match function one could try following too.
your_curl_command | awk '
match($0,/^<html.*lang="[^"]*/){
val=substr($0,RSTART,RLENGTH)
sub(/.*lang="/,"",val)
print val
}
'
Explanation: Adding detailed explanation for above.
your_curl_command | awk ' ##Starting awk program from here.
match($0,/^<html.*lang="[^"]*/){ ##using match function to match regex starting from <html till lang=" till next 1st occurrence of "
val=substr($0,RSTART,RLENGTH) ##Creating val which has substring of matched values.
sub(/.*lang="/,"",val) ##Substituting everything till lang=" with NULL in val here.
print val ##printing val here.
}
'
Another variation using gnu awk and a pattern with a capture group using match:
match(string, regexp [, array])
curl -Ls yahoo.com | awk 'match($0, /<html [^<>]*lang="([^"]*)"/, a) {print a[1]}'
Output
en-US
The pattern matches
<html Match literally
[^<>]* Match 0+ any char except < or >
lang=" Match literally
([^"]*) Capture group 1 (denoted by a[1] in the example code) matching 0+ times any char except "
" Closing double quote

Adjusting column padding in bash

Any idea how can I put the output as the following?
Input:
1 GATTT
2 ATCGT
Desired output:
1 GATTT
2 ATCGT
I tried the following and it did not work
cut -c7,1-6,8-
$ awk -v OFS='\t' '{print $1,$2}' input
1 GATTT
2 ATCGT
or
$ awk '{print $1 "\t" $2}' input
SED can also be used:
sed "s/[:digit:]* .*/ &/g" input
1 GATTT
2 ATCGT
I'm assuming that the original whitespace were 6 spaces based on your cut command. The easiest way to knock this out with simple bash commands is using a tab for separation on the output.
echo " 1 GATTT" | cut -d ' ' -f 7- | tr ' ' '\t'
The cut command makes the delimeter a space character and takes from field 7 on. Then the tr (translate) command converts the remaining space to a tab.

Can I catch the value by using bourne shell script?

When I type some command in openwrt, the result is like this.
Security Signal(%) Mode
WPA2 86 on
WPA2 42 on
In this result, I want to catch the signal value(86) in first column.
How can i catch the value by using bourne shell script?
Plus, luci.sys.call function is only used in cbi file for making Luci, isn't it?
Try also
HereYourCommand | awk 'NR==2 { print $2 }'
The awk program prints the second field (aka column) of the second record (aka line).
The following should do:
HereYourCommand | head -2 | tail -1 | tr -s ' ' | cut -d' ' -f2
Replace HereYourCommand with your call to openwrt.
The explanation:
head -2: pick up just the first two lines.
tail -1: from this two lines, pick up the last line.
tr -s ' ': replace multiple spaces with a single one.
cut -d' ' -f2: pick up the 2nd field from the remaining line.
cat test|tail +2|tr -s '\s\t' ' '|cut -d' ' -f2
tail +2 skips first line, then I am replacing spaces or tabs with single space and cut get second field.
output:
4
5
8
input:
x y z
1 4 7
2 5 7
4 8 0

Match List of Numbers in For Loop in Bash

I have a script that loops over a curl command, which pulls in data from an API.
LIST_OF_ID=$(curl -s -X POST -d "username=$USER&password=$PASS&action=action" http://link.to/api.php)
for PHONE_NUMBER in $(echo $LIST_OF_ID | tr '_' ' ' | awk '{print $2}');
do
$VOIP_ID = $(echo $LIST_OF_ID | tr '_' ' ' | awk '{print $1}')
done
I also have a variable of 16 numbers in the range of "447856321455"
NUMBERS=$(cat << EOF
441111111111
441111111112
441111111113
... etc
)
The output on the API call is:
652364_441111111112
As you may notice I have taken the output and cut it into 2 parts and put it in a variable.
What I need is to match the 6 digit code from the output where the number in the output, matches with the number in the variable.
I've attempted it using if statements but I can't work my head around the correct way of doing it.
Any help would be appreciated.
Thank you.
I would do it using join rather than a loop in bash. Like this:
curl -s -X POST -d "$PARAMS" "$URL" | sort \
| join -t _ -2 2 -o 2.1 <(sort numbers.txt) -
What this does is take the sorted output from curl and join it with the sorted contents of numbers.txt (you could use $NUMBERS too), using _ as the separator, using column 2 of file 2 which is - meaning stdin (from curl). Then output field 2.1 which is the six-digit ID.
Read why-is-using-a-shell-loop-to-process-text-considered-bad-practice and then do something like this:
curl ... |
awk -v numbers="$NUMBERS" -F'_' '
BEGIN { split(numbers,tmp,/[[:space:]]+/); for (i in tmp) nums[tmp[i]] }
$2 in nums
'
but to be honest I cant really tell what it is you are trying to do as the numbers in your sample input don't seem to match each other (what does in the range of "447856321455" mean and how does it relate to $NUMBERS containing 441111111111 through 441111111113 and how does any of that relate to match the 6 digit code) and the expected output is missing.

grep from first part of a line before delimiter

I have to grep from this data- test1.txt:
1 - Billing_Type
604 - Customer_Name
2 - Contact_Name
3 - Customer_Phone_Number
4 - Contact_Phone_Number
5 - Customer_Type
6 - Reason_Code
7 - CALLE 1
8 - CALLE 2
9 - NUMERO
10 - ID
11 - Service Address
1700001031 - Serial_Number
1700001008 - STB_REF_AP_ID
1700001027 - Smart_Card_ID
I am comparing the first part of the file e.g. 1700001031, 1, 8 etc in a loop from a file and then copying the second part of the file in a variable like the Serial_Number, Billing_Type, CALLE 2.
This is the statement i have used :
sample statement
grep -w 1 test1.txt | cut -d'-' -f2 |tr -d ' '
but the problem with this statement is that for values 1 and 2 is will output two lines.
for 1 as ID,it will print:
Billing_Type
CALLE 1
as the ATTR_NAME also contains the word value 1 in 'CALLE 1'.
how do i search in the first part only and get the second without making any extra files?
You really want to use awk not grep for this:
$ awk -F' - ' '$1==1{print $2}' file
Billing_Type
$ awk -F' - ' '$1==7{print $2}' file
CALLE 1
$ awk -F' - ' '$1==1700001031{print $2}' file
Serial_Number
This does a numeric equality test against the first field $1 and if the line matches it's prints the second field $2 using - as the field separator.
With GNU Grep you could do the following but the awk approach is definitely the way to go:
$ grep -Po '^1\s+-\s+\K.*' file
Billing_Type
$ grep -Po '^7\s+-\s+\K.*' file
CALLE 1
$ grep -Po '^1700001031\s+-\s+\K.*' file
Serial_Number
This matches the start of string of the string ^ then a given number followed by one or more spaces, a dash and more spaces \s+-\s+, \K is part of perl compliant regular expressions so don't count on it being widely available, what it does is makes all the previously matched part of the string be forgotten about. Finally we match the rest of the line .* and only this is printed thanks to the -o option and the \K.
The approach with sed would be to match the line then subsitute the start of the line with an empty string:
$ sed -rn '/^1\s/{s/^[0-9]+\s+-\s+//p}' file
Billing_Type
$ sed -rn '/^7\s/{s/^[0-9]+\s+-\s+//p}' file
CALLE 1
$ sed -rn '/^1700001031\s/{s/^[0-9]+\s+-\s+//p}' file
Serial_Number
You just need to add ^ before search ID number to your command
grep -w '^1' test1.txt | cut -d'-' -f2 |tr -d ' '

Resources