so I'm using lsusb | grep -n -Eo '[0-9]{1,3}' to filter the data of my command inside my terminal. The thing is, I want to filter it even more and get the two specific rows that stands for a USB bus and device number.
Here is an output for example (in here I want to have the 002 and 001 from line 1 and 001 003 from line 2):
1:002
1:001
1:1
1:6
1:000
1:3
1:3
1:0
2:001
2:003
2:13
2:3
2:352
2:6
Can anyone tell me how to do so? plus if you have any easier way to get the value of the bus and device number out of the terminal using lsusb I'm open to suggestions.
lsusb:
lsusb:
Bus 002 Device 001: ID 2b1d:2341 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 31d3:3125 IMC Networks
Bus 001 Device 002: ID 31d3:67c1 IMC Networks
Bus 001 Device 004: ID 1245:1222 SteelSeries ApS
Bus 001 Device 001: ID 1315:3232 Linux Foundation 2.0 root hub
awk might be a better choice than grep here.
lsusb | awk '{print $2" "substr($4, 1, length($4)-1)}'
With GNU grep, you can get only numbers that follow Bus or Device:
grep -noP '(Bus|Device) \K\d+'
I want to have the 002 and 001 from line 1 and 001 003 from line 2
Not very clear on this, but if you want only first two lines that match, you can use:
grep -m2 -noP '(Bus|Device) \K\d+'
Related
I am trying to sort and join two files which contain IP addresses, the first file only has IPs, the second file contains IPs and an associated number. But sort acts differently in these files. here are the code and outcomes:
cat file | grep '180.76.15.15' | sort
cat file | grep '180.76.15.15' | sort -k 1
cat file | grep '180.76.15.15' | sort -t ' ' -k 1
outcome:
180.76.15.150 987272
180.76.15.152 52219
180.76.15.154 52971
180.76.15.156 65472
180.76.15.158 35475
180.76.15.15 99709
cat file | grep '180.76.15.15' | cut -d ' ' -f 1 | sort
outcome:
180.76.15.15
180.76.15.150
180.76.15.152
180.76.15.154
180.76.15.156
180.76.15.158
As you can see, the first three commands all produce the same outcome, but when lines only contain IP address, the sorting changes which causes me a problem trying to join files.
Explicitly, the IP 180.76.15.15 appears at the bottom row in the first case (even when I sort explicitly on the first argument), but at the top row in the second case and I can't understand why.
Can anyone please explain why is this happening?
P.S. I am ssh connecting through windows 10 powershell to ubuntu 20.04 installed on VMware.
sort will use your locale settings to determine the order of the characters. From man sort also:
*** WARNING *** The locale specified by the environment affects sort order.
Set LC_ALL=C to get the traditional sort order that uses native byte values.
This way you can use the ASCII characters order. For example:
> cat file
#a
b#
152
153
15 4
15 1
Here all is sorted with the alphabetical order excluding special characters, first the numbers, then the letters.
thanasis#basis:~/Documents/development/temp> sort file
15 1
152
153
15 4
#a
b#
Here all characters count, first #, then numbers, but the space counts also, then letters.
thanasis#basis:~/Documents/development/temp> LC_ALL=C sort file
#a
15 1
15 4
152
153
b#
The networksetup -listallhardwareports command returns the hardware MAC addresses of all network devices in a Mac.
How can I reliably extract 00:0c:29:5b:14:b3 from stdout when line order isn’t known ahead of time (therefore I can’t use networksetup -listallhardwareports | sed -n 4p | awk '{print $3}')?
Hardware Port: Wi-Fi
Device: en0
Ethernet Address: 00:0c:29:5b:14:b3
Hardware Port: Bluetooth PAN
Device: en3
Ethernet Address: e1:7e:be:a6:0b:12
networksetup -listallhardwareports| awk -v RS= '/en0/{print $NF}'
00:0c:29:5b:14:b3
Explanation: This awk command is converting all multi-line records into single line records. This is done by unsetting(-v RS=) awk's default record separator(RS). Later matching if any line(or record) is containg en0 string in it.
Here is a slightly different twist that doesn't join lines, but instead just uses a simple flag to indicate that en0 was found as the second field and then outputs the last field on the next line and exits:
networksetup -listallhardwareports |
awk '$2=="en0" { nextmac=1; next } nextmac==1 {print $NF; exit}'
00:0c:29:5b:14:b3
Both approaches are fine, it's just a bit easier for me to wrap my head around processing each record rather than joining them. Six-to-one is a 1/2 dozen to another.
I have a bash script I made which when run on each of my computers, detects the number of CPU cores, HDDs/partitions, battery present or not, etc, and generate a conkyrc file to display the relevant info for that PC using the style I prefer in my conky. I am having difficulty determining whether the PC is on a wired or wireless internet connection however.
Does anyone know a way to determine the type of connection with a bash script?
Try this:
tail -n+3 /proc/net/wireless | grep -q . && echo "We are wireless"
Details
On a hardwired system, the contents of /proc/net/wireless consist of two header lines:
# cat /proc/net/wireless
Inter-| sta-| Quality | Discarded packets | Missed | WE
face | tus | link level noise | nwid crypt frag retry misc | beacon | 22
On a system with an active wireless interface, there will be a third line displaying data about that interface.
The command above works as follows
The tail -n+3 command is used to remove the header.
The grep -q . command tests for the presence of subsequent lines that are present if a wireless interface is active.
Alternative
iwconfig is a utility that reads information from /proc/net/wireless:
iwconfig 2>&1 | grep -q ESSID && echo "We are wireless"
I have a log file that generates timestamp and command logging on separate lines. I'd like to strip out the timestamp and save just the "user: command" list. I've tried several permutations of sed to replace or delete the data between strings, but it always oversteps the bounds of the command. Current log output similar to:
USER 001
6:32am
USER 001
random bash command or output 001
USER 002
7:41am
USER 002
random bash command or output 002
USER 001
7:43am
USER 001
random bash command or output 003
USER 002
7:43am
USER 002
random bash command or output 004
Desired output:
USER 001
random bash command or output 001
USER 002
random bash command or output 002
USER 001
random bash command or output 003
USER 002
random bash command or output 004
Looks like this will do:
sed -ri 'N; /^.*\n[0-9]/d'
(Assumes GNU sed.)
It processes the file two lines at a time.
On each cycle:
sed automatically reads one line into the pattern space.
The N command appends to the pattern space a newline and the next line.
If the pattern space matches "any text, newline, digit", then delete
it (and therefore don't auto-print it).
Otherwise, auto-print it.
If file is in same format all time, you can just remove the line like this:
awk 'NR%4!=1 && NR%4!=2' file
USER 001
random bash command or output 001
USER 002
random bash command or output 002
USER 001
random bash command or output 003
USER 002
random bash command or output 004
Or you can use it like this:
awk '!(NR%4==1 || NR%4==2)' file
Given the dmesg log output, specifically a line in it, for eg:
NET: Registered protocol family 10
in a script I want to have a defined variable like $net_version that will check if I define it with a value of 10, if it matches the one found in dmesg.
I looked both at sed and awk, however for awk I cannot find the correct way of stripping the output to just match the variable with the last word in that dmesg line.
I think this is a simple one, however I'm having an issue identifying the correct way of doing it.
I'd advise against using unanchored regular expressions. If "NET: Registered protocol family 100" is not supposed to be matched, then some of the other answers here may give you false positives.
In the following grep solution, note the anchor at the end of the regex. Also, the -q option for grep makes it "quiet" so that it can be used simply to inform your if.
#!/bin/sh
val="10"
if dmesg | grep -q "^NET: Registered protocol family ${val}$"; then
echo "matched"
fi
Alternately, you could use awk, but you'll want two conditions -- one to match the string on the line, and one to match the variable.
awk -v val="10" '/^NET: Registered protocol family / && $NF==val { print "matched" }'
Or you could do it with a single string match:
awk -v val="10" '$0 == "NET: Registered protocol family "val { print "matched" }'
or if you want to use sed to strip output for evaluation in a shell script, you could do it this way:
#!/bin/bash
val=$(dmesg | sed -ne '/^NET: Registered protocol family /{;s///p;q}')
if [ "$val" -eq "10" ]; then
echo "matched"
fi
The sed script here looks a little complex, so lets' break it out...
the -n option tells it not to print output by default,
we start by searching for a line containing the NET: text, and if found,
we substitute the text we found for "nothing" (thus stripping it),
the p at the end of the command tells it to print the output if the substitution was successful, and
we quit, thus protecting ourselves from multiple occurrences of the string.
If instead you want to be able to handle multiple occurrences in your dmesg file, you might have to run things through a loop:
#!/bin/sh
dmesg \
| sed -ne '/^NET: Registered protocol family /{;s///p;q}') \
| while read val; do
if [ "$val" -eq "10" ]; then
echo "matched"
fi
done
I've split the dmesg pipe onto multiple lines for easier reading here, but you can make it all one line in your script.
You can use sed to print matching lines:
var=10
sed -n "/NET: Registered protocol family $var/p" file
-n avoids printing all lines.
"/NET: .... $var/p" users doubleq quotes to have the variable expanded.
/p prints matched lines.
Or of course grep:
$ grep "NET: Registered protocol family $var" file
Example
$ cat a
NET: Registered protocol family 10
NET: Registered protocol family 7
NET: Registered protocol family hello
bye
$ var=10
$ sed -n "/NET: Registered protocol family $var/p" a
NET: Registered protocol family 10
$ var=7
$ sed -n "/NET: Registered protocol family $var/p" a
NET: Registered protocol family 7
$ var=5
$ sed -n "/NET: Registered protocol family $var/p" a
$
With grep:
$ var=10
$ grep "NET: Registered protocol family $var" a
NET: Registered protocol family 10
Need to do similar thing but to find USB flash drive info. I start with the command:
dmesg | grep -i 'scsi' | grep -i removable
I get 2 results of:
[ 3.197914] sd 2:0:0:0: [sdc] Attached SCSI removable disk
[22373.515566] sd 3:0:0:0: [sdd] Attached SCSI removable disk
I need to then loop to get the sdc and sdd values and plug into var $SDDRV to run next cmd of:
fdisk -l | grep -i disk | grep ${SDDRV}
If the disk is not actually attached (this case sdc), the fdisk cmd produces nothing, but since in this case sdd is active, the result is:
Disk /dev/sdd: 63.2 GB, 63216549888 bytes
I then need to parse out the flash drive size, which is 63.2 GB (My 64GB flash), and since size is greater that 63GB set var SDNAM to "64Gig" (name for flash). I have a 1GB, 2GB, 16GB and 64GB, so must have logic to get the right name for any/all inserted drives and as you see the size linux sees does not equal the mfg size label. Not sure why, but still need to get right name for each inserted device.
Next I need to run command:
df -h | grep ${SDDRV}
Resulting in, I'm showing the column lables from 'df':
Filesystem Size Used Avail Use% Mounted on
/dev/sdd1 59G 11M 59G 1% /media/ndavis/USB DISK
From this I must parse the 'Available Space' and the 'Mount Point'
If I process all this right I then should have:
Drive Name,
Drive Size,
Space Available,
Mount Point
I then create a single VAR with all these and export it so this can be used by other scripts needing USB flash drive info.