Random Tech Notes

Here are some random notes that I find useful. I also tend to forget and use as reference.

== LINKS ==
iproute2 cheat sheet by dmbaturin http://baturin.org/docs/iproute2/
The MTU/MSS calculator, encapcalc

Speedtests
The BEST -> http://www.dslreports.com/speedtest
https://www.speedtest.net
http://compari.tech/speed
SpeedOf.Me
bandwidthplace.com

data transfer calculator
http://techinternets.com/copy_calc


[] Vim reference
:e filename (open filename)
:q! (quit, don’t save)
:w (write/save)
:wq (write and quit)
:x (write if changed, otherwise exit)
:changes (show list of edits in the buffer)
a (insert after)
A (insert after line)
h j k l (left, down, up, right)
$ (move to end of line)
^ or 0 (move to beginning of line)
G (move to end of file)
gg (move to top of file)
gUU (uppercase entire line)
guu (lowercase entire line)
gUw (uppercase a word, u lowers)
:n (move to “n” line, n=number)
x (delete to the right)
X (delete to the left)
D (delete to the end of line)
dd (delete current line)
yy (yank/copy current line)
V (begin highlight, up and down to select “y” to yank selection)
vn (yank “n” lines below cursor, n=number)
p (put/paste)
u (undo)
ctrl+r (redo)
/string (search for “string”)
n (search for next string match)
:s/yellow/green/gc (replace yellow with green on current line, g is for global, each match is replaced in a line, instead of the first match in a line. c is for confirm/ask)
:%s/yellow/green/g (replaces yellow with green on the entire page)
:%s:/usr/local/bin:/opt/users/bin:g (use something other than / as delineation so you don’t have to escape “/”. Like this nasty example: :s/\/usr\/local\/bin/\/usr\/loca\/bin)
:%s#http://jasonschaefer.com#https://jasonschaefer.com#g (Switch the delimiter to # for strings with : and / to avoid annoying escapes!)
:2,$s/ */ /g (After the 2nd line, replace 1 (2 spaces with a *) or more spaces with 4 spaces, globally)

strftime
$ echo the day and time is currently `date +"%a at %T"`
https://foragoodstrftime.com/
Sat, Jun 23 22:01:40 “%a, %b %d %T”
Sat, Jun 23 2018 7:04 PM “%a, %b %d %Y %l:%M %p”

[] bash tricks
stop bash history:
unset HISTFILE

[] find command
find . -name "name" -exec [command goes here] {} \;
find . -type d -exec chmod 750 {} \;
recursively changes type directories to user=rwx, group=r-x, other=—
find . -type f -exec chmod 664 {} \;
recursively changes type file user=rw-, group=rw-, other=r– (so that files are not executable)
find /home/BACKUP -mtime +14 -exec rm -fr {} \;
-mtime options:
n exactly n days
+n more than n days
-n less than n days

find files that are newer than specified date time:
find /path/ -newermt 2018-01-15

use -ls to output long listing of matches
find /path/ -newermt “may 21 2018 16:00” -ls
yesterday or today can be used instead

find files between a date reference
finds files between 16:00 and 16:47 on may 21
find /path/ -newermt “may 21 2018 16:00” ! -newermt “may 21 2018 16:47”

to convert all backslash \ to forward slash /
find . -type f -iname *.xml -exec sed -i 's:\\:/:g' {} \;

find hard links (directories have multiple links so use type file and not with 1 link)
find /path -type f ! -links 1

find directories, with emails, with less than 330 files (emails)
find /home/user/Maildir/ -type d -name cur -exec tree -RaFC –filelimit 330 {} \;

find quantity (310-320) of files under any directory named cur
find /home/user/Maildir -type d -name cur -exec bash -c “echo -n ‘{} ‘; ( ls ‘{}’/ | wc -l )” \; | grep ‘ 3[12][0-0]$’

find -exec has two variants:
this variant runs the command (echo in this case) once per match
-exec echo '{}' \;
echo ./match1
echo ./match2
echo ./1match

and this runs the command once against all matches
-exec echo '{}' \+
echo ./match1 ./match2 ./1match

[] Image Conversions and Resizing in batch groups
This will resize all jpg’s in the current directory “.” to 1024×768 and put them in the directory small
find . -iname "*.jpg" | xargs -l -i convert -resize 1024x768 {} small/{}
or a better use of find and convert would be
find -iname "*.jpg" -exec convert -resize 20% {} {}_small.jpg \;

You can replace the “convert -resize” with convert -quality 85% to compress the images instead.

merge multiple images into one pdf
convert blah-page1.png blah-page2.png blah.pdf
wildcards work
convert *.png blah.pdf
convert is a part of imagemagick

[] Edit EXIF data on images
Using exiftool to shift wrong date caused by a camera with the wrong time. man Image::ExifTool::Shift.pl for a manual.
example:
exiftool "-AllDates+=1:0:21 0:0:0" *.JPG
This adds (+=) 1 year, 0 months and 21 days, 0 hrs, 0 min, 0 sec to all files ending in .JPG

[] tar
tar with various exclude examples
tar zcfv backup-website.tar.gz --exclude=stuff --exclude=path/to/stuff --exclude="more stuff with spaces in the name" --exclude=*.wild /home/website

[] chmod tricks
chmod can be used in a way where it preserves executable permissions, if they are already present. using upper X
chmod -R u=rwX,g=rwX,o=rX /path/to/
This recursively (-R) sets user and group to rw- dirs and files that don’t already have executable permissions (the X is similar to x but preserves executable perms if they were preexisting). If the dir or file has any executable permissions then it sets user and group to rwx. This can be handy if you want to change lots of files and dirs at once but not make files executable. For instance, chmod -R u=rwx,g=rwx would blanket files and dirs making them all executable. Of course, using find with type and exec can more explicitly set permissions. But it will reset any executable files as well. Thus the benefit of chmod and X.
To see what files are executable, if any, do
find /path/ -executable -type f

Proper permissions for wordpress:
chown www-data:wwwmaster -R /home/www/
find /home/www/ -type f -exec chmod g=rws {} \;
find /home/www/ -type d -exec chmod g=rwxs {} \;

[] How to recursively force a group permission + umask per user on gnu/linux.
First you can recursively set the desired owner and group. Recursive is optional, only needed if you have sub dirs.
chown -R root.users /path/to/dir
Then force all files and directories created under /path/to/dir to be owned by the creator and the group will be set to “users” group. Notice the chmod g+rwxs is adding the (s)etGID bit for the group.
find /path/to/dir -type d -exec chmod g+rwxs {} \;
You will notice that when a user now creates files or directories under /path/to/dir they come out as (on a typical system)
-rw-r--r-- 1 jason users 0 Aug 29 16:49 this is a file
drwxr-sr-x 2 jason users 6 Aug 29 16:49 this is a directory

You will need to change your umask. You can find it under your home directory in ~/.profile
Uncomment or add umask 002 so that the group “users” will be able to read your files and execute your directories.

[] changing default new file or directory permissions, umask on debian wordaround for http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=646692
change /etc/login.defs
UMASK 022 (equivalent to 644/rw-r–r– files and 755/rwxr-xr-x directories)
to
UMASK 002 (equivalent to 664/rw-rw–r– files and 775/rwxrwxr-x directories)

If that doesn’t work. Enable the pam_umask module like this.
echo "session optional pam_umask.so usergroups" >> /etc/pam.d/common-session


[] Cleanup /etc/passwd and /etc/group

sort /etc/passwd in place
pwck -s

sort /etc/group in place
grpck -s

[] Rename multiple files

remove space from all files ending in .mp3
rename 's/ //'g *.mp3
rename all files ending in .ZIP to .zip
rename 's:\.ZIP:\.zip:' *.ZIP

[] search and replace text within a group of files

find /etc/NetworkManager/system-connections/ -exec sed -i "s/mac-address=0:1e:4c:27:40:00/mac-address=EC:55:F9:0F:5D:00/g" {} \;
use -name, -type to refine the match if you need.

jedit is a gui program that can do this.

[] SSH stuffs

copy your ssh public key to remote hosts ~/user/.ssh/authorized_keys file
ssh-copy-id user@host

Use ‘ssh-add’ to add your private key to the ssh-agent, so you don’t need to type your passphrase each time you ssh someplace.

create a listen socket on your local computer, that redirects port to a host on remote network (10.9.8.2)
ssh -L localhost:3389:10.9.8.2:3389 user@host
-L [bind_address:]port:host:hostport
(now you can rdesktop to localhost and it will connect to the remote 10.9.8.2)
rdesktop -g90% localhost

create a remote socket that forwards port 2222 on localhost of server to port 22 on initiating host.
Useful for remote support sessions.
ssh -R localhost:2222:localhost:22 user@hostname
-R [bind_address:]port:host:hostport
(now you can ‘ssh -p2222 localhost’ from the server and reach the host)

create a socks4/5 proxy over ssh
ssh -D8080 user@hostname
(now you can configure your browser to use socks5 proxy at localhost:8080 and you can reach the remote networks web servers, or just use it to securely proxy your web traffic through the remote hosts internet connection)

[] Sending mail with telnet:
telnet hostname 25
helo me
mail from:myaddress@mydom.com
rcpt to:youraddress@yourdom.com
data
This is a test
.

(thats a newline [enter] – period – and another newline [enter])

[] Fix MBR for windows
http://ms-sys-free.sourceforge.net/

from gnulinux:
ms-sys -m /dev/hda

from msdos or nt recovery console:
fdisk /mbr

[] Batch and snippets (yuck)
http://www.allenware.com/icsw/icswidx.htm

echo Cleanup .bak files older than 7 days
forfiles /p d:\backup /m *.bak /d -7 /c "cmd /c del /q @path"

echo Set variable date as yyyymmdd
set date=%date:~-4,4%%date:~4,2%%date:~-7,2%
echo %date%

[] Filesystem stuff

make clone image of sda
dd if=/dev/sda of=/dev/sdb bs=4096 conv=notrunc,noerror

notrunc or ‘do not truncate’ maintains data integrity by instructing dd not to truncate any data.
noerror instructs dd to continue operation, ignoring all input errors. Default behavior for dd is to halt at any error. Useful when imaging damaged drives.
bs=4096 sets the block size to 4k, an optimal size for hard disk read/write efficiency and therefore, cloning speed.

backup mbr
dd if=/dev/sda of=mbr.backup bs=512 count=1

check status of dd transfer (use pgrep to find process id, kill to send user define signal 1, dd progress will be displayed on terminal where dd was run)

kill -USR1 $(pgrep ^dd)

mount image
losetup /dev/loop0 sda.img
mount /dev/loop0 /mnt

Initialize all SATA buses:
for x in /sys/class/scsi_host/host*; do echo "- - -" > $x/scan; done

xfs filesystem and xfsprogs
Determine the amount of fragmentation on sda2
xfs_db -c frag -r /dev/sda2

Filesystem re-organizer, by default, with no arguments. It re-organizes files in mounted partitions for 2 hours. Use -t to change the time.)
xfs_fsr
These tools reside in the xfsdump package

[] Recover Files
testdisk (recover lost partitions)

photorec (part of the testdisk suite)

foremost sda.img
-t (type doc,jpg,exe etc. all is default)
-a (no error detection, recovers partial files)
-d (indirect block, use for nix filesystems)
-o (output dir)
-T (timestamp output dir)

extundelete /dev/sda1 –restore-directory /home/jason

https://help.ubuntu.com/community/DataRecovery
https://wiki.archlinux.org/index.php/File_Recovery#Working_with_Raw_Disk_Images

mdadm RAID
http://www.ducea.com/2009/03/08/mdadm-cheat-sheet/

[] KVM Virtualization

Interface config for bridging to virtualized client /etc/network/interfaces
wireless interfaces rarely ever support bridging.

# The primary network interface
iface eth0 inet manual
auto br0
  iface br0 inet dhcp
  bridge_ports eth0
  bridge_stp off
  bridge_waitport 0
  bridge_fd 0

Resize/Add storage to kvm image:
dd if=/dev/zero of=myvirtualhost.img bs=1M count=78k oflag=append conv=notrunc
notrunc MUST be used or else append will overwrite beginning of image.

Alternately, creates a sparse file which suffers from fragmentation and possible corruption if host system doesn’t provide proper space for the sparse image to fill into. So its not recommended.
truncate -s +10G image.raw
Alternate method sparse:
qemu-img create -f raw addon.img 10G
be sure to make a backup of original.img
now you can append addon.img to original.img
cat addon.img >> original.img

Now, boot the .img vm and use cfdisk to partition the new space. Reboot, and build a filesystem OR boot the instance with a live distro that has gparted and merge/resize the new partition with the old.

Convert a qcow2 image to raw image and remove the sparsity (-S 0 is non-sparse).
qemu-img convert -p -O raw -S 0 win7pro.qcow2 win7pro.img

Also, fallocate is a great way to allocate kvm images. “preallocation is done quickly by allocating blocks and marking them as uninitialized, requiring no IO to the data blocks. This is much faster than creating a file by filling it with zeroes”
fallocate -l 128GiB virtualhost.img

write zeros to the image so that you can make a sparse copy of the image for backup. Without the zeros the sparse copy won’t have the ability to sparsify
dd if=/dev/zero of=virtualhost.img conv=notrunc,fdatasync bs=1M count=128K


preferred method for expanding a disk image (make a backup!!)
original.img is 64GB and you want to expand it to 128
fallocate -l 128GiB original.img
use gparted to expand the partition and filesystem into the extra space.

Backup virtual images into a sparse file to save space
cp --sparse=always winblows7.img SNAPSHOTS/winblows7.img_oct06-2017
Be sure to unsparsify the file if you need to restore it!
cp --sparse=never SNAPSHOTS/winblows7.img_oct06-2017 winblows7.img

[] KVM with Windows

The best way to get virtio is on install. Download the block driver floppy image and attach it, I use virt-manager. Set your hard drive to type virtio and start your windows install. It will will prompt you to press f6 to install third party drivers. Then press S (you have a disk from a third party manufacturer, your floppy image)

If you already have a disk type IDE and want it to be virtio (better). Then do this:
1. Create a temporary image
kvm-img create -f qcow2 temp-virtio.img 1G
2. Shutdown your virtual machine and attach temp-virtio.img as a hard drive, as type virtio.
3. Attach the virtio-win-x.x.x.vfd (i used the one from fedoraproject.org, see below) to you virtual machine
4. Boot up and install the drivers
5. Shutdown, remove the old hard drive image and re-add it as type virtio
6. Boot up and since you already installed the drivers it will boot. Otherwise, you get BSOD..
(You can remove the temp-virtio.img and floppy image).. All done.

For network drivers.. Shutdown, set the “device model” to virtio. Attach the NETKVM-xxxx.iso as a cdrom. Bootup and install drivers. yay!

virtio network drivers, quamranet
http://sourceforge.net/projects/kvm/files/kvm-driver-disc/

virtio block device drivers (aka, hard drive)
http://alt.fedoraproject.org/pub/alt/virtio-win/latest/images/bin/ or
http://sourceforge.net/projects/kvm/files/kvm-guest-drivers-windows/

[] Debian package tricks

list all packages that come from a particular repository, this case “testing”
for p in $(dpkg -l | awk ‘/ii/{ print $2 }’); do for i in $(apt-cache policy “$p” | awk ‘/Installed/{ print $2}’); do apt-cache policy “$p” | grep -A1 ‘\*\*\*\ ‘$i” | if grep -q testing; then echo $p; fi; done; done

[] Windows Policy

run gpedit.msc to edit policy

to backup or move to new host, copy the following
%systemroot%\system32\GroupPolicy\Machine and User dirs

to apply changed policy’s
gpupdate /force

[] RDP tricks

plain old vnc is no more, not to say its not useful but xrdp is a super combo rambo pack. when it comes to ease of use, autostart scripts in debian, built in encryption, performance and cross platform the xrdp project rules the roost. Follow these simple steps.
on server: apt-get install xrdp
done;
on client: rdesktop -g95% [server name or ip]
-g is for geometry, look it up in man rdesktop
done; wow!
obviously, you will need rdesktop or some other remote desktop protocol installed on the client.
If you have issues with the arrow up and down keys minimizing and maximizing your X terminal do the following:
In gnome, use gnome-control-center -> Go to keyboard ‘Shortcuts’ tab, ‘Windows’ on the left pane -> select super+up and super+down shortcuts -> press backspace to disable these shortcuts on these actions.

xfreerdp is a fork of rdesktop that has newer features like certificate verification that comes with new versions of MS Windows.

xfreerdp +clipboard /v:10.11.12.66 /u:accounting /drive:share,/home/accounting/share /smart-sizing /workarea
see the new documentation for details https://github.com/FreeRDP/FreeRDP/wiki/CommandLineInterface

SeamlessRDP http://www.cendio.com/seamlessrdp/
rdesktop -A -s "c:\seamlessrdp\seamlessrdpshell.exe c:\program files\internet explorer\iexplore.exe" -u username -p password hostname
uhhh, for the record I have NEVER gotten this to work properly. Please contact me if you have!

[] Self Signed certificate on debian, the easiest way possible
make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /etc/ssl/private/hostcert.crt
This script will ask for a domain and write the certificate. to /etc/ssl/private/hostcert.crt

https://www.ssllabs.com/ssltest/analyze.html

[] OpenVPN reference
analyze a certificate
openssl x509 -text -in jason.crt
openssl x509 -noout -in jason.crt -subject

verify a certificate revocation list
openssl crl -text -noout -in crl.pem

recommended ovpn:

remote [host] 1194 udp
float
client
dev tun
mute 5
nobind
comp-lzo
tls-exit
remote-cert-tls server
resolv-retry infinite
explicit-exit-notify
keepalive 10 60
ping-timer-rem
persist-tun
persist-key
#redirect-gateway def1
ca ca.crt
cert [user].crt
key [user].key

[] tshark and tcpdump packet capture

To run tshark remotely and pipe results back to wireshark locally. Can be tcpdump instead of tshark. Needs root access..

ssh root@server 'tshark  -w -' | wireshark -k -i -

Examples of filter
http://wiki.wireshark.org/CaptureFilters
also check the man page for pcap-filter
man pcap-filter
Common uses —
tshark -i eth0 host 10.0.1.10
tshark -i eth0 net 10.0.1.0/24
tshark -i eth0 port 80
tshark -i eth0 port 80 and host 10.0.1.10 and not port 22
tshark -i eth0 tcp port 80 or tcp port 443 -V -R “http.request || http.response”

[] OpenWRT Notes

OpenWRT failsafe recovery mode
http://wiki.openwrt.org/doc/howto/generic.failsafe

flashing with atftp (follow the instuctions for particular device at http://wiki.openwrt.org/toh/start)
curl -T openwrt-xxxx-xxxxx-squashfs-factory-xxxx.img tftp://192.168.1.1
or the more complicated annoying way
atftp --trace --tftp-timeout=1 --put --local-file openwrt-xxxxx-xxxxx.img 192.168.1.1

Setup SSL/TLS (https) for Luci web interface and disable insecure plaintext (http)
opkg install luci-ssl
be sure the following is commented out in /etc/config/uhttpd
# HTTP listen addresses, multiple allowed
# list listen_http 0.0.0.0:80
# list listen_http [::]:80

Also change the cert px5g options to be more unique and add more days to the self signed certificate.
/etc/init.d/uhttpd restart


Disable/Enable Wireless on a schedule, automatically

The first line will use bridge control to remove the wireless interface (wlan0-1) from the lan bridge (br-lan) at 22:30. The next cron will add the interface back at 6:00. Redirect (>) all output to dev null. Substitute wlan0-1 for whichever interface you need to. Add this to crontab:
30 22 * * * brctl delif br-lan wlan0-1 >/dev/null 2>&1
0 6 * * * brctl addif br-lan wlan0-1 >/dev/null 2>&1

use “brctl show” to see which interfaces are in the bridge:

root@OpenWRT:~# brctl show
bridge name	bridge id		STP enabled	interfaces
br-lan		7fff.c6031578e51d	no		eth0.1
							wlan0
							wlan0-1

[] Cron and wget with Afraid free DNS
Its best to use curl. Install curl with opkg update and then opkg install curl or apt or yum, etc.
*/10 * * * * /usr/bin/curl -k https://freedns.afraid.org/dynamic/update.php?[random string]

wget is overly complicated… but if its all you got, then its great.
*/10 * * * * /usr/bin/wget --no-check-certificate -O - https://freedns.afraid.org/dynamic/update.php?[random string] > /dev/null 2>&1

add to /etc/rc.local so that it updates immediately on bootup. This doesn’t always work if the wan interface isn’t operational at time of execution.

# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.
/usr/bin/curl -k https://freedns.afraid.org/dynamic/update.php?[random string]
exit 0

[] MYSQL

mysql> create database newdb;

mysql> CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON newdb . * TO 'newuser'@'localhost';

(GRANT ALL PRIVILEGES ON [database name].[table name] TO ‘[username]’@’localhost’;)

mysql> SET PASSWORD FOR 'newuser'@'localhost' = PASSWORD('newpassword');

mysql> DROP USER 'newuser'@'localhost';

update table g2_PluginMap and set column g_active to 0 where column g_pluginID is captcha. This disables the captcha plugin in gallery2
UPDATE g2_PluginMap SET g_active = '0' WHERE g_pluginId = captcha;
DELETE FROM g2_FactoryMap WHERE g_implModuleId='captcha';

(unrelated to mysql, you will need to clear the cache to fully disabled this plugin -> http://your-domain.tld/gallery/lib/support/index.php

[] RSYNC
rsync highlights:
typical use —
rsync -av --delete --stats --exclude media/* /home/ /mnt/usb/rsync-home-mirror
copy [a]rchive, [v]verbosely, –delete any files on the destination that don’t exist in source (mirror), show transfer [stat]istics, [exclude] any files inside directory media, copy contents of /home/ into /mnt/rsync-home-mirror

advanced use — useful for copying entire OS
rsync -aAHXi --super --numeric-ids /source/ /destination
-a archive, -A copy ACL, -H copy hard links, -X copy extended attributes, -i show changes, –numeric-ids preserves uid and gid numerically instead of by name.

Use -n to do a dry run! Especially valuable when using –delete switch.

You can think of a trailing / on a source as meaning “copy the contents of this directory” as opposed to “copy the directory by name”

rsync over ssh
rsync -aiz /source/path username@192.168.1.10:/remote/destination/path
rsync -aiz user@host:/remote/source /local/destination

[] fstrim
fstrim one-liner for cron. every sunday at 12:30 timestamp the log and include two partitions, / and /home.
30 12 * * 0 /bin/date +\%c > /tmp/fstrim.log && /sbin/fstrim -v / >> /tmp/fstrim.log 2>&1 && /sbin/fstrim -v /home >> /tmp/fstrim.log 2>&1

[] wget

for range in {1..7};do wget http://URL/Episode$range.mp3 ; done
for range in {{1..3},{5..7}};do wget http://URL/Episode$range.mp3 ; done
Mirror entire site with wget
wget --mirror -p --convert-links http://URL
or
wget --recursive --no-clobber --page-requisites --html-extension --convert-links --no-parent --domains website.org http://website.org
[] ffmpeg

convert video to webm
ffmpeg -i be-hose.mp4 -acodec libvorbis -aq 5 -ac 2 -qmax 25 -threads 2 be-hose.webm

[] encrypted partitions
#to create
cryptsetup luksFormat /dev/sdb
cryptsetup luksOpen /dev/sdb backupdrive
mkfs.xfs /dev/mapper/backup
mount /dev/mapper/backup /mnt/
umount /mnt
cryptsetup luksClose backup

#to open
cryptsetup luksOpen /dev/sdd1 [devmappername]

#to close
cryptseup luksClose [devmappername]

#dump hd encrypted headers (if drive fs is damaged, you can restore from this dump)
cryptsetup luksHeaderBackup /dev/sdd1 > file.bk

#to restore header
cryptsetup luksRestore /dev/sdd1 –header-backup-file file.bk

[] booting os manually from grub2
set root=(hd0,gpt2)
linux /boot/vmlinuz-2.6.18-6-686 root=/dev/sda1
initrd /boot/initrd.img-2.6.18-6-686
boot

[] booting into password recovery using grub

new methond: append systemd.debug_shell to linux line of grub. system boots normal and ctrl+alt 9  will have root shell that bypasses password prompt.

old method: append init=/bin/bash to linux line of grub. system boots in read only mode mount -o remount,rw / and run passwd to change password.

[] Text Manipulation, simple and common techniques

file.txt contains:

a b c d e
f g h i j

awk '{print $2 "\t" $5}' file.txt
b e
g j

awk '{print $2","$5}' file.txt
b,e
g,j

cut -d " " -f 2 file.txt
b
g

cut -d " " -f 2,4 file.txt
b d
g i

cut -d " " -f 3-5 file.txt
c d e
h i j

MATH with awk!
file.txt contains:

1 2 3 4
5 6 7 8

awk '{print $2 + $4}' file.txt
6
14

awk '{print $2 * $3}' file.txt
6
42

[] EXIM
consult the oracle: zless /usr/share/doc/exim4-base/README.Debian.gz

dpkg-reconfigure exim4-config
update-exim4.conf; service exim4 stop; service exim4 start

Enable tls:
enable the following in /etc/default/exim4
SMTPLISTENEROPTIONS='-oX 25:465:587 -oP /run/exim4/exim.pid'

enable plain_server: PLAIN and LOGIN in /etc/exim4/exim4.conf.template

swaks -a -tls -q HELO -s smtp.schaeferconsulting.com -au test -ap '<>'

for x in $(mailq | grep frozen | sed -e ‘s/^……….//’ -e ‘s/ .*//’); do exim -Mrm $x; done

[] GPG
jason gets the public key for geoff from keyserver
gpg --keyserver keys.openpgp.org --recv-keys 6058D99C
or
gpg --keyserver keys.openpgp.org --search-keys email@address
signs the key with his B0EE80C1 key
gpg --default-key B0EE80C1 --sign-key 6058D99C
export the signed key to send to geoff
gpg --output 6058D99C.asc --export --armor 6058D99C
send geoff_6058D99C.asc to geoff
———-
geoff receives key and imports
gpg --import geoff_6058D99C.asc
sends the updated key to keyserver
gpg --keyserver keys.openpgp.org --send-keys 6058D99C

gpg --keyserver keys.openpgp.org --refresh-keys 6058D99C
gpg --list-sigs 6058D99C
gpg --list-keys

[] GIT

this is how to checkout a sub directory of a git repository, without downloading the entire git project.

git clone --filter=blob:none --no-checkout --depth 1 --sparse https://github.com/XRPLF/xrpl-dev-portal.git
cd xrpl-dev-portal/
git sparse-checkout add content/_code-samples/build-a-desktop-wallet
git checkout
ls content/_code-samples/build-a-desktop-wallet/

[] Python PIP

new in debian 12 (how to avoid breaking apt and pip)

mkdir python
python3 -m venv python/
source python/bin/activate
pip install esptool meshtastic

now its all self contained in “python” directory. In the future, to use this python environment, source like so

source python/bin/activate

and your shell will look something like this
(python-env) [jason@lap ~/python] $