Scripts > Manual Labor
I needed to change the layout of some text. Repetitive work is something I hate, so I wrote a script to do it for me. Doing it manually would have been faster though.
Simple Plan
I recently had some issues with my AdGuard Home instance. The DHCP server was giving the wrong DNS server to my devices. So I wanted to migrate to another DHCP server.
The biggest part of this migration would be copying the static leases to the new server. As AdGuard Home does not have an option to export them, I copy-pasted them from the web interface in to a text file. It gave me a list that looks something like this (but a lot longer):
aa:aa:aa:aa:aa:aa
10.0.1.111
devicea
aa:aa:aa:aa:aa:ab
10.0.1.112
deviceb
aa:aa:aa:aa:aa:ac
10.0.1.113
devicec
aa:aa:aa:aa:aa:ad
10.0.1.114
deviced
The tool I'm migrating to uses yaml for its configuration and I needed the data in this format:
hosts:
- mac: aa:aa:aa:aa:aa:aa
ip: 10.0.1.111
name: devicea
- mac: aa:aa:aa:aa:aa:ab
ip: 10.0.1.112
name: deviceb
- mac: aa:aa:aa:aa:aa:ac
ip: 10.0.1.113
name: devicec
- mac: aa:aa:aa:aa:aa:ad
ip: 10.0.1.114
name: deviced
I did not want to do this manually so I wrote a script to do it.
The Script
The script looks like this:
#!/bin/bash
# init variables & constants
INFILE=$(cat "$1")
OUTFILE=$2
looper=0
# clear file and write top key
echo "hosts:" | tee "${OUTFILE}"
# loop lines and write key:values
for LINE in $INFILE; do
if test $looper -eq 0; then
echo " - mac: ${LINE}" | tee -a leases.yml
looper=1
elif test $looper -eq 1; then
echo " ip: ${LINE}" | tee -a leases.yml
looper=2
elif test $looper -eq 2; then
echo " name: ${LINE}" | tee -a leases.yml
looper=0
fi
done
The first rule is the shebang, it defines the interpreter that should be used to execute the script.
Next I define my variables and CONSTANTS. INFILES
contains the content of the text file I just created. This text file will be passed as the first parameter. OUTFILE
is the name of the file I will write the result to. This will be passed to the script as the second parameter. The looper
variable will be used to count to 3 (0-2), as every lease uses 3 rules (mac, ip and name).
Then I write hosts:
to initialize the output file. This will clear the file if it exists, or create a new one if it doesn't.
For writing to the output file, I use
tee
instead of a redirect (>
). Thetee
command writes output to a file and to the standard output. If the-a
flag is used withtee
, it will append the text to file instead of overwriting it.
Next I will start a loop that goes over every line of the text file. I use if statements to check the current value of looper
. If it is 0, I will append - mac:
in front of the line. This is because we know the mac address will always be on the first line. The completed rule will be written to the bottom of the output file. We also increment looper
so we know where we are. For the next line, looper
will be 1. We write ip:
in front of the line, append it to the output file an again increment looper
. When we reach the next line, we add name:
in front of it, and append it to the output file. Now we reset the looper
back to 0 so we know the next line will start a new device.
If we now run the script we get this:
[jeroen@GHOST Scripting1]$ ./leases.sh ./leasesExample.txt ./leasesExample.yml
hosts:
- mac: aa:aa:aa:aa:aa:aa
ip: 10.0.1.111
name: devicea
- mac: aa:aa:aa:aa:aa:ab
ip: 10.0.1.112
name: deviceb
- mac: aa:aa:aa:aa:aa:ac
ip: 10.0.1.113
name: devicec
- mac: aa:aa:aa:aa:aa:ad
ip: 10.0.1.114
name: deviced
The generated yaml file is displayed on the screen and is written to the file you passed as the second parameter (leaseExample.yml
in my case).
That's all, a simple script for a simple task. If you got any questions, don't hesitate to contact me.
When writing shell scripts, I highly recomend to use ShellCheck. It's a simple tool that checks your shell script on a lot of common issues and best practices.