How can I programmatically insert a MAC address into /etc/network/interfaces? - string

I am trying to write a script that uses a user-created MAC address when using the wlan0 interface.
To test, I made a file called testFile.txt, which is a copy of /etc/network/interfaces. If there are interfaces after wlan0, I cannot use echo "$var" >> testFile.txt because that simply adds the text to the end.
I am able to find the end of the wlan0 interface text, but I am not sure how to insert there. Below is what I currently have:
#!/bin/bash
echo "Enter MAC Address"
read var
log=$(cat testFile.txt | grep -o "wlan0.*" | grep -o dhcp)
echo $log
echo $log prints dhcp.
I tried adding | echo "hwaddress ether $var" >> testFile.txt to $log but that still appends to the end of the file.
How do I insert directly after $log?

The Problem
Useless use of cat. Don't do that.
You're not using the right tool for the job. Use GNU sed to make life easier on yourself.
The Solution
# Insert hwaddress line into /etc/network/interfaces.
read -p "Enter MAC Address: "
sudo sed -i.bak "/iface wlan0/a\ hwaddress $REPLY" /etc/network/interfaces
# Replace existing hwaddress line in /etc/network/interfaces.
read -p "Enter MAC Address: "
sudo sed -ri.bak "s/(hwaddress).*/\1 $REPLY/"

You may want to use sed to insert the MAC address. If you want to insert it at the end of the line with wlan0, that would be
sed "s/\(wlan0.*\)/\1 $var/" testFile.txt > testFile.txt.tmp
If that works, then
mv testFile.txt.tmp testFile.txt

you need a different tool, SED for example
$ seq 5 | sed '/3/ s/.*/something else/'
1
2
something else
4
5
for example you can Substitute the line with '3' by 'something else' - and there is no limits

Related

How can I delete multiple characters in my bash script?

I want to create a bash script on Linux, which will only tell me my ip-adress, netmask and broadcast. Right now it shows more than that though, so I would like to remove a specific number of characters from my variable.
Example:
What I have
ip=Hello world!
What I want
ip=Hello
So how can I remove a specific amount of characters from the back of the variable?
I tried multiple things that I found online, but couldn't get it working the way I want it to.
with bash's substring extraction:
$ my_var="Hello world!"
$ my_var=${my_var:0:-6}
$ echo $my_var
Hello
You could pipe through grep and only output the matching portion
echo "ip=hello world" | grep -o "ip=\w*"
Output: ip=hello
Another point is you can use sed command.
For, example
$ my_var="Hello world"
$ my_var=$(echo $my_var | sed -e 's/ .*//')
$ echo $my_var
Hello
or another approach using cut
$ my_var="Hello world"
$ my_var=$(echo $my_var | cut -d ' ' -f1)
$ echo $my_var
Hello
Important - do not type ! symbol in double-quotes

bash + how to capture IP address from line

I have many configuration files ,
the line that start with LINE word have IP address
My target to read the line that start with LINE word from the file and print only the IP address
The problem is that IP address can be in any field in the line so I can’t capture the IP according to field number
example
grep LINE file1.txt
LINE /home/Ariate/run.pl "Voda STS 4 Test - " "102841" && ssh 17.77.170.130 -p 2022
grep LINE file2.txt
LINE /home/Ariate/run.pl 137.77.170.30 "Voda STS 4 Test - " "102841" && ssh ACTIVE
please advice how to capture the IP address from the line ( solution can be also with perl one liner )
expected results
echo $IP_FROM_LINE
17.77.170.130
echo $IP_FROM_LINE
137.77.170.30
perl -MRegexp::Common=net -lne 'print $1 if /^LINE.*\b($RE{net}{IPv4})/'
Using this grep -oE:
grep -oE '\d+\.\d+\.\d+\.\d+' file
17.77.170.130
137.77.170.30
OR else:
grep -oP '\d+\.\d+\.\d+\.\d+' file
The following will get you the desired IP addresses:
grep -oP '^LINE.*\b\K\d+\.\d+\.\d+\.\d+' file
To place the result in a variable as request, you'll need to iterate of the results as follows:
grep -oP '^LINE.*\b\K\d+\.\d+\.\d+\.\d+' file |
while read IP_FROM_LINE ; do
echo $IP_FROM_LINE
done
grep -oE '[0-9]{2,3}(\.[0-9]{2,3}){3}'
matches
17.77.170.130
137.77.170.30
or
grep -oP '\d{2}(\.\d{2}){3}'
if your grep supports -P option.
both of them works with the data you have given.
But if you want really worried of what to be matched, use
grep -Eo '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
which would match excat ip addresses.

Bash Scripting : edit output of a variable

I read some data out of a file, used grep for the only two columns needed, and redirected the output into a variable.
My script looks like this:
#!/bin/bash
cat hosts.cfg | grep 'address\|host_name' | sed -e 's/\<address\>//g' | while read line; do
echo $line | sed 's/host_name//g' | sed -r 's/\s+//g' ;
done
The output looks something like this now:
Host1
xx.xx.xx.xx
Host2
xx.xx.xx.xx
The problem is that hosts and ips must be saved into an array, not a file!
Output must look like this:
Host1(tab)xx.xx.xx.xx
Host2(tab)xx.xx.xx.xx
You are looking for process substitution. $(command), or old-style in `s.
(sorry, the description of how it should work is not clear enough for me to show modified version of your code)
You can use awk:
echo $output | awk 'NR%2{printf $0"\t";next;}1'
To save any command output, wrap it in backticks, or the newer (but less backward compatible) $(command) style substitution. E.g.:
result=`echo $output | awk 'NR%2{printf $0"\t";next;}1'`
using sed 'N;s/\n/\t/g'
change
Host1
xx.xx.xx.xx
Host2
xx.xx.xx.xx
to
Host1(tab)xx.xx.xx.xx
Host2(tab)xx.xx.xx.xx
You can use "set" to get faster output
exg:
I have file best2,
# cat best2
Host1 xx.xx.xx.xx Host2 xx.xx.xx.xx
make a script called: tabcheck.sh
# cat tabcheck.sh
#!/bin/bash
out=$(cat best2)
set $out
echo -e "$1\t$2\n$3\t$4"
# ./tabcheck.sh
Host1 xx.xx.xx.xx
Host2 xx.xx.xx.xx
If you use shift command(Usually only nine command line arguments can be accessed using positional parameters. The shift command gives access to command line arguments greater than nine by shifting each of the arguments.) as well.
Thanks.

Separate IPs From Ports using Shell Script?

I was just wondering how I would go about writing a shell script to separate proxy IPs from their ports.
The proxies are stored in this format
ip:port
ip:port
ip:port
How can I use a shell script to separate the IP on the left side of the colon from the Port on the right side, and put the IP and Port lists in separate .txt files with the same order? Is this even possible?
If the proxies are listed that way in a file, say proxy.txt, then all you need is cut:
cut -f1 -d: proxy.txt > proxy_ip.txt
cut -f2 -d: proxy.txt > proxy_port.txt
Try something like this:
#!/bin/bash
ips="1.2.3.4:123 2.3.4.5:356 4.5.6.7:576"
# or get IPs from stdin
# split them
ips_array=($ips)
for w in ${ips_array[#]}
do
echo $w | sed -e 's/:.*$//g' >> ips.txt
echo $w | sed -e 's/^.*://g' >> ports.txt
done
Key is using the ($ips) to split the list up.
EDIT:
I just realized that you didn't format your question correctly so it's not a single line with IP:PORTs separated by spaces, but one on a line by itself. You just need this then:
#!/bin/bash
while read w
do
echo $w | sed -e 's/:.*$//g' >> ips.txt
echo $w | sed -e 's/^.*://g' >> ports.txt
done
And you read from stdin.

Get the last 4 characters of output from standard out

I have a script that is running and uses
lspci -s 0a.00.1
This returns
0a.00.1 usb controller some text device 4dc9
I want to get those last 4 characters inline such that
lspci -s 0a.00.1 | some command to give me the last 4 characters.
How about tail, with the -c switch. For example, to get the last 4 characters of "hello":
echo "hello" | tail -c 5
ello
Note that I used 5 (4+1) because a newline character is added by echo. As suggested by Brad Koch below, use echo -n to prevent the newline character from being added.
Do you really want the last four characters? It looks like you want the last "word" on the line:
awk '{ print $NF }'
This will work if the ID is 3 characters, or 5, as well.
Using sed:
lspci -s 0a.00.1 | sed 's/^.*\(.\{4\}\)$/\1/'
Output:
4dc9
Try this, say if the string is stored in the variable foo.
foo=`lspci -s 0a.00.1` # the foo value should be "0a.00.1 usb controller some text device 4dc9"
echo ${foo:(-4)} # which should output 4dc9
I usually use
echo 0a.00.1 usb controller some text device 4dc9 | rev | cut -b1-4 | rev
4dc9
If the real request is to copy the last space-separated string regardless of its length, then the best solution seems to be using ... | awk '{print $NF}' as given by #Johnsyweb. But if this is indeed about copying a fixed number of characters from the end of a string, then there is a bash-specific solution without the need to invoke any further subprocess by piping:
$ test="1234567890"; echo "${test: -4}"
7890
$
Please note that the space between colon and minus character is essential, as without it the full string will be delivered:
$ test="1234567890"; echo "${test:-4}"
1234567890
$
Try using grep:
lspci -s 0a.00.1 | grep -o ....$
This will print last 4 characters of every line.
However if you'd like to have last 4 characters of the whole output, use tail -c4 instead.
One more way to approach this is to use <<< notation:
tail -c 5 <<< '0a.00.1 usb controller some text device 4dc9'
instead of using named variables, develop the practice of using the positional parameters, like this:
set -- $( lspci -s 0a.00.1 ); # then the bash string usage:
echo ${1:(-4)} # has the advantage of allowing N PP's to be set, eg:
set -- $(ls *.txt)
echo $4 # prints the 4th txt file.

Resources