Pull A Section Of A Grepped Line - regex

I need help pulling Bluetooth addresses from a grepped line.
The addresses are like so:
address: 80-82-23-aa-1d-6f, not connected, not favourite, paired, name: "DeviceName", recent access date: 2019-07-22 02:24:44 +0000
address: 4c-6b-e8-01-6d-1e, not connected, not favourite, paired, name: "OtherHeadPhones", recent access date: -
I'm able to grep a line for the device I want, where '$1' is a device name and believe I need to pipe this into a regex grep, but can't workout the regex statement.
blueutil --paired | grep '$1' | grep <something>
I'd require the address line like: '80-82-23-aa-1d-df'. For whichever device name I pass the script ($1)
Any help, and explanation would be much appreciated!
Thanks

blueutil --paired | grep '(your regex returning only the line(s) you want)' | grep -P -o '[\da-f]{2}(-[\da-f]{2}){5}' should help.
-P means that the regex is Perl-compatible.
-o means that only the matches are to be output.
[\da-f] is a hexadecimal digit.
{2} meads that there are two of them in each address part.
{5} means that the address consists of six parts, but the first part, without a hyphen before, has already been matched.

Probably Awk is a better solution in terms of legibility and maintainability.
blueutil --paired |
awk -v pattern="$1" '$0 ~ "name: \042" pattern "\042" {
addr = $2; sub(",", "", addr); print addr }'
This contains some guesswork as to which part of the output from blueutil you want to match -- in particular, it interpolates the input to search for the string in double quotes after name: and a single space.

You can do it using GNU sed:
grep "$1" file_name|sed -r 's/address: (.*),\s+not connected.*/\1/'

Related

How to retrieve only ticket number from string

I have the following pipeline step which run a Regex
- TICKET_NAME="$(echo $BRANCH_NAME | sed -E 's~^(.*/){0,1}((ABV|ASD|WSX)-[0-9]{2,6})-.*~\2~I')"
Basically, the $BRANCH_NAME can be the following
fix/ABV-123-test-version
ABV-4233-test-another-thing
feature/-ASD-my-feature
What I would like is, to always retrieve the ticket number which is always starting with ABV|ASD|WSX and always end after the number.
so ABS-123 or ASD-3423 the number can be any number but it will always be the same pattern.
my current regex works, but it also capute the prefix so fix/ABV-123
I would like only the ABV-123
Using sed
$ sed -En 's~([^/]*/)?([AW][BS][VDX]-[0-9]+).*~\2~p' input_file
ABV-123
ABV-4233
With your shown samples please try following GNU awk code. Written and tested in GNU awk. Simple explanation would be, setting RS(Record separator) to ((A(BV|SD))|WSX)-[0-9]+ to get ABV OR ASD OR WSX followed by a - followed by 1 or more digits and then in main program printing RT values if its not null.
awk -v RS='((A(BV|SD))|WSX)-[0-9]+' RT'{print RT}' Input_file
This is much easier with grep -o:
grep -Eo '(ABV|ASD|WSX)-[0-9]+' file
ABV-123
ABV-4233

Given a phrase grab the next string from a multiline sentence using sed RegEx

I'm using sed to obtain a specific string (0x0296cc83474725ddca19a9feefb3aec3602d9073688a4db6885695320cd2a738) from an output. This string comes next to Contract address:
This is what I'm trying currently.
UPDATE: out put has newlines.
$ echo $output
Starknet plugin using the active environment.
Deploying contract.cairo/contract.json
Deploy transaction was sent.
Contract address: 0x0296cc83474725ddca19a9feefb3aec3602d9073688a4db6885695320cd2a738
Transaction hash: 0x3f60551591f6abb9c79044ce15de4260eb169af2931abdc279e73f6428fc12d
Succeeded
$ ADDRESS=$(echo $output | sed -r "s/.*Contract address: (\w*).*/\1/")
$ echo "Address: $ADDRESS" # This is not working
I know how to grab the contract addres using awk but for this case I have to use sed.
You can use a parameter expansion to trim the string up to just before the value you want, and then another one to trim from the next whitespace.
tail=${output#*Contract address: } # or Contact Hash: if that's what you actually meant
address=${tail%% *}
Tangentially, prefer lower case for your private variables; see also Correct Bash and shell script variable capitalization
sed does not portably support \w and anyway, using an external process is wasteful when the shell can do this using internal facilities entirely. Your attempt was also flawed in that you should generally quote your variables unless you specifically require the shell to perform whitespace tokenization and wildcard expansion on the value.
If indeed $output contains newlines which were obscured when you echoed it without quoting, then you might want to use
tail=${output#*$'\n'Contract address: }
address=${tail%%$'\n'*}
You can use
sed -rn 's/.*Contract address: ([^ ]*).*/\1/p'
sed -rE 's/.*Contract address: ([^ ]*).*/\1/p'
Details:
-rn / -En - POSIX ERE syntax enabled, and default line output behavior suppressed
.*Contract address: ([^ ]*).*: regex matching any text, Contract address: , then any zero or more chars other than a space are captured into Group 1 (\1), and then the rest of the string is matched
\1 - the whole match is replaced with Group 1
p - prints the result of the successful substitution.
See the online demo:
#!/bin/bash
output='Starknet plugin using the active environment. Deploying contract.cairo/contract.json Deploy transaction was sent. Contract address: 0x0296cc83474725ddca19a9feefb3aec3602d9073688a4db6885695320cd2a738 Transaction hash: 0x3f60551591f6abb9c79044ce15de4260eb169af2931abdc279e73f6428fc12d Succeeded'
ADDRESS=$(echo $output | sed -rn 's/.*Contract address: ([^ ]*).*/\1/p')
echo "Address: $ADDRESS"
# => Address: 0x0296cc83474725ddca19a9feefb3aec3602d9073688a4db6885695320cd2a738
Using a simple awk:
address=$(echo "$output" | awk -F ': ' '$1 == "Contract address" {print $2}')
echo "$address"
0x0296cc83474725ddca19a9feefb3aec3602d9073688a4db6885695320cd2a738
Avoid using all caps variable names in shell to avoid clashes with reserved shell env variables.
Using sed
$ address=$(sed -n '/^Contract address: \(.*\)/s//\1/p' <<< "$output")
$ echo "Address: $address"
Address: 0x0296cc83474725ddca19a9feefb3aec3602d9073688a4db6885695320cd2a738

How to get the release value?

I've a file with the below name formats:
rzp-QAQ_SA2-5.12.0.38-quality.zip
rzp-TEST-5.12.0.38-quality.zip
rzp-ASQ_TFC-5.12.0.38-quality.zip
I want the value as: 5.12.0.38-quality.zip from the above file names.
I'm trying as below, but not getting the correct value though:
echo "$fl_name" | sed 's#^[-[:alpha:]_[:digit:]]*##'
fl_name is the variable containing the file name.
Thanks a lot in advance!
You are matching too much with all the alpha, digit - and _ in the same character class.
You can match alpha and - and optionally _ and alphanumerics
sed -E 's#^[-[:alpha:]]+(_[[:alnum:]]*-)?##' file
Or you can shorten the first character class, and match a - at the end:
sed -E 's#^[-[:alnum:]_]*-##' file
Output of both examples
5.12.0.38-quality.zip
5.12.0.38-quality.zip
5.12.0.38-quality.zip
With GNU grep you could try following code. Written and tested with shown samples.
grep -oP '(.*?-){2}\K.*' Input_file
OR as an alternative use(with a non-capturing group solution, as per the fourth bird's nice suggestion):
grep -oP '(?:[^-]*-){2}\K.*' Input_file
Explanation: using GNU grep here. in grep program using -oP option which is for matching exact matched values and to enable PCRE flavor respectively in program. Then in main program, using regex (.*?-){2} means, using lazy match till - 2 times here(to get first 2 matches of - here) then using \K option which is to make sure that till now matched value is forgotten and only next mentioned regex matched value will be printed, which will print rest of the values here.
It is much easier to use cut here:
cut -d- -f3- file
5.12.0.38-quality.zip
5.12.0.38-quality.zip
5.12.0.38-quality.zip
If you want sed then use:
sed -E 's/^([^-]*-){2}//' file
5.12.0.38-quality.zip
5.12.0.38-quality.zip
5.12.0.38-quality.zip
Assumptions:
all filenames contain 3 hyphens (-)
the desired result always consists of stripping off the 1st two hyphen-delimited strings
OP wants to perform this operation on a variable
We can eliminate the overhead of sub-process calls (eg, grep, cut and sed) by using parameter substitution:
$ f1_name='rzp-ASQ_TFC-5.12.0.38-quality.zip'
$ new_f1_name="${f1_name#*-}" # strip off first hyphen-delimited string
$ echo "${new_f1_name}"
ASQ_TFC-5.12.0.38-quality.zip
$ new_f1_name="${new_f1_name#*-}" # strip off next hyphen-delimited string
$ echo "${new_f1_name}"
5.12.0.38-quality.zip
On the other hand if OP is feeding a list of file names to a looping construct, and the original file names are not needed, it may be easier to perform a bulk operation on the list of file names before processing by the loop, eg:
while read -r new_f1_name
do
... process "${new_f1_name)"
done < <( command-that-generates-list-of-file-names | cut -d- -f3-)
In plain bash:
echo "${fl_name#*-*-}"
You can do a reverse of each line, and get the two last elements separated by "-" and then reverse again:
cat "$fl_name"| rev | cut -f1,2 -d'-' | rev
A Perl solution capturing digits and characters trailing a '-'
cat f_name | perl -lne 'chomp; /.*?-(\d+.*?)\z/g;print $1'

“sed” command to remove a line that matches an exact string on first word

I've found an answer to my question here: "sed" command to remove a line that match an exact string on first word
...but only partially because that solution only works if I query pretty much exactly like the answer person answered.
They answered:
sed -i "/^maria\b/Id" file.txt
...to chop out only a line starting with the word "maria" in it and not maria if it's not the first word for example.
I want to chop out a specific url in a file, example: "cnn.com" - but, I also have a bunch of local host addressses, 0.0.0.0 and both have some with a single space in front. I also don't want to chop out sub domains like ads.cnn.com so that code "should" work but doesn't when I string in more commands with the -e option. My code below seems to clean things up well except that I can't get it to whack out the cnn.com! My file is called raw.txt
sed -r -e 's/^127.0.0.1//' -e 's/^ 127.0.0.1//' -e 's/^0.0.0.0//' -e 's/^ 0.0.0.0//' -e '/#/d' -e '/^cnn.com\b/d' -e '/::/d' raw.txt | sort | tr -d "[:blank:]" | awk '!seen[$0]++' | grep cnn.com
When I grep for cnn.com I see all the cnn's INCLUDING the one I don't want which is actually "cnn.com".
ads.cnn.com
cl.cnn.com
cnn.com <-- the one I don't want
cnn.dyn.cnn.com
customad.cnn.com
gdyn.cnn.com
jfcnn.com
kermit.macnn.com
metrics.cnn.com
projectcnn.com
smetrics.cnn.com
tiads.sportsillustrated.cnn.com
trumpincnn.com
victory.cnn.com
xcnn.com
If I just use that one piece of code with the cnn.com chop out it seems to work.
sed -r '/^cnn.com\b/d' raw.txt | grep cnn.com
* I'm not using the "-e" option
Result:
ads.cnn.com
cl.cnn.com
cnn.dyn.cnn.com
customad.cnn.com
gdyn.cnn.com
jfcnn.com
kermit.macnn.com
metrics.cnn.com
projectcnn.com
smetrics.cnn.com
tiads.sportsillustrated.cnn.com
trumpincnn.com
victory.cnn.com
xcnn.com
Nothing I do seems to work when I string commands together with the "-e" option. I need some help on getting my multiple option command kicking with SED.
Any advice?
Ubuntu 12 LTS & 16 LTS.
sed (GNU sed) 4.2.2
The . is metacharacter in regex which means "Match any one character". So you accidentally created a regex that will also catch cnnPcom or cnn com or cnn\com. While it probably works for your needs, it would be better to be more explicit:
sed -r '/^cnn\.com\b/d' raw.txt
The difference here is the \ backslash before the . period. That escapes the period metacharacter so it's treated as a literal period.
As for your lines that start with a space, you can catch those in a single regex (Again escaping the period metacharacter):
sed -r '/(^[ ]*|^)127\.0\.0\.1\b/d' raw.txt
This (^[ ]*|^) says a line that starts with any number of repeating spaces ^[ ]* OR | starts with ^ which is then followed by your match for 127.0.0.1.
And then for stringing these together you can use the | OR operator inside of parantheses to catch all of your matches:
sed -r '/(^[ ]*|^)(127\.0\.0\.1|cnn\.com|0\.0\.0\.0)\b/d' raw.txt
Alternatively you can use a ; semicolon to separate out the different regexes:
sed -r '/(^[ ]*|^)127\.0\.0\.1\b/d; /(^[ ]*|^)cnn\.com\b/d; /(^[ ]*|^)0\.0\.0\.0\b/d;' raw.txt
sed doesn't understand matching on strings, only regular expressions, and it's ridiculously difficult to try to get sed to act as if it does, see Is it possible to escape regex metacharacters reliably with sed. To remove a line whose first space-separated word is "foo" is just:
awk '$1 != "foo"' file
To remove lines that start with any of "foo" or "bar" is just:
awk '($1 != "foo") && ($1 != "bar")' file
If you have more than just a couple of words then the approach is to list them all and create a hash table indexed by them then test for the first word of your line being an index of the hash table:
awk 'BEGIN{split("foo bar other word",badWords)} !($1 in badWords)' file
If that's not what you want then edit your question to clarify your requirements and include concise, testable sample input and the expected output given that input.

Filter out IP using regex and sed

I'm having real trouble converting my regular expression into a working sed command on Centos 5.5.
I want to filter the IP address out of a string:
"example.org has address 123.45.67.890" -> "123.45.67.890"
My regular expression so far is:
/([a-zA-Z\. ]+)([0-9\.]+)/
And an example of my command using sed is:
host example.org | grep 'has address' | sed 's/\([a-zA-Z\\. ]+\)\([0-9\\.]+\)/\2/'
But all I get back from that command is the input to sed: "example.org has address 123.45.67.890"
Any ideas?
host example.org | awk '/has address/ {print $4 }'
Here's a very simple way to do it without a regex:
host example.org | grep "has addres" | awk '{print $4}'
You don't really need sed for this. You could use cut instead to parse the spaces:
host example.org | grep 'has address' | cut -d' ' -f4
This just takes the 4th word, when delimited by spaces.
Your ([a-zA-Z\. ]+) captures everything before the IP address and includes that in the match. It will also cause matching to fail if the domain name has any numbers in it. Use a lookbehind:
/(?<has address )\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/
You apparently need to use Perl mode for sed to support lookbehinds. You could also use capture groups. If you want a more discriminating pattern (i.e. only match stuff that looks very strongly like an IP address), you can try this:
/(?<has address )(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\b/
That should match four numbers from 0-255, delimited by dots and preceded by 'has address '.
Using GNU grep:
host example.org | grep -Po '.*has address \K[0-9.]*'
host exmaple.org | sed -n 's/^.* (.*)$/\1/p'