2020.07.22 edit: There’s a followup to this post, that you can read here. It has an updated version of the script.
For the past weeks, I’ve been reading through O’Reilly’s Sed & Awk, 2nd Edition, to learn those powerful commandline tools. The other day, I had a practical problem for which Sed seemed like the perfect solution out of the box. It’s small, and quite trivial, but it made me proud nonetheless.
In brief, the situation I run into is that I run Manjaro Linux using the i3WM windows manager on both my desktop and laptop, and I would like to share configuration files between them; however, due to their different resolutions, I want most but not all settings to be shared. Specifically, I have a few windows I keep on a scratchpad (basically: floating windows that you can hide, as well as keep consistent across workspaces). I still tweak these files every so often as I try to add features I like or adjust the look of this or that. I then share the config file between my two PCs, which leads me to having to adjust a few settings:
# Laptop configuration
for_window [class="^popup_term$"] resize set 960 540
for_window [class="^popup_note$"] resize set 455 758
bindsym $mod+equal [class="^popup_note$"] scratchpad show, move position 906 5
# Desktop configuration
#for_window [class="^popup_term$"] resize set 960 540
#for_window [class="^popup_note$"] resize set 455 1070
#bindsym $mod+equal [class="^popup_note$"] scratchpad show, move position 2540 324
By the way, you can see the constant tweaks here, because I used to have the popup-term class take different sizes depending on PC or laptop, but I recently settled on using the same resolutions for both. So, that one, for instance, will have to be edited out again into the general settings. The settings above used to be part of those settings, but I split them off to separate the desktop/laptop-specific configurations. Then, using my newly-gained Sed skills I made a tiny script that just comments out one set of code and removes the comments for the other:
# Commands to switch to desktop configuration
# Comment out laptop configurations
/# Laptop/,/^$/{
/# Laptop/b
/^$/b
/^#/!s/\(.*$\)/\#\1/
}
# Uncomment desktop configurations
/# Desktop/,/^$/{
/# Desktop/!s/#//
}
It’s a fairly straightforward substitution: anything between the start of the Laptop section to the first blank line gets subjected to the code. Using a branch to nowhere (using a branch without a label in Sed means it skips to the end of the script), I make sure to skip the title (I want to keep that a comment), and to skip the blank line (just to keep it looking neat). Then, a basic regex takes every line that doesn’t start with a comment and replaces those lines with a # and the line. Lastly, we do the inverse in the Desktop section: we simply replace the # character with nothing in all lines except the title. Since we’re only removing a character, there’s no need to filter out anything else.
Because I have two scripts, one for the move to desktop and one to laptop, I made a small bash script to switch between them:
#!/bin/bash
# Bash script to switch over i3wm configs
computer=
# Back up file, using \cp to avoid interactive alias
\cp config -f config.old
# Catch potential errors
if [ $# != 1 ]
then echo "Error: please provide one argument."; exit 1
fi
# Check what file to change
case $1 in
-d|--desktop) computer=desktop;;
-l|--laptop) computer=laptop;;
*) echo "Select either -d, --desktop, -l, or --laptop"; exit 1
esac
echo "Swapping configuration over to $computer."
# Implement the change using sed
if [ $computer == desktop ]
then sed -i -f desktop.sed config
else sed -i -f laptop.sed config
fi
This way, I don’t have to take the individual steps myself, and just use the one command to take care of it. Plus, if one day I figure out a way to check if the config file has changed from a previous version, I could use this to automate an adjustment. For now, I’m just happy I figured out a practical means of automating something I used to have to do manually each time I edited the configuration file.