Troubleshooters.Com and T.C Linux Library Present

Linux Quick Hacks


Contents

Introduction

This document contains minisolutions for many problems, gathered and recorded from the year 2000 to the present. Many have been removed after becoming obsolete. They're ordered by date written, so an entries farther down the document were written later.

Ascii Character Lister

To list printable characters and their ascii values, do the following:

perl -e 'foreach $x (32..126){print "_" . chr($x) . "  " . $x . "\n"}'

To find the ascii code for a specific character (other than the space character, use $ in this example), do this:

perl -e 'foreach $x (32..126){print "_" . chr($x) . "  " . $x . "\n"}' | grep '_\$'

Normal characters don't need and can't use the backslash, so to find the asci value of lower case 'd' you'd do this:

perl -e 'foreach $x (32..126){print "_" . chr($x) . "  " . $x . "\n"}' | grep '_d'

To find the character corresponding to an ascii value, do this (example uses 100 as the ascii value):

perl -e 'foreach $x (32..126){print "_" . chr($x) . "  " . $x . "\n"}' | grep ' 100'

Man pages formatted as text

Man pages look great on console screens, but piped to files or to browsers they quickly degenerate into cluttered conglomerations of reverse linefeeds and backspaces designed to simulate "bold" on your console screen. You get rid of the clutter by piping the output of man through thecol command. With no args, col blows off the reverse linefeeds but leaves the backspaces (^H). The command you want (using the ls man page as an example) is:

man ls | col -bx > myfile.txt

The preceding command writes the man page to myfile.txt, without backspaces (the -b) and with spaces substituted for tabs (-x).

Shellscript File Tests

Here's a script to test for a file's existence:

if [ -e $file ]; then
 ./myUtil $file
fi
TESTMEANING
[ -b $file ] True if file exists and is block special.
[ -c $file ] True if file exists and is character special.
[ -d $file ] True if file exists and is a directory.
[ -e $file ] True if file exists.
[ -f $file ] True if file exists and is a regular file.
[ -g $file ] True if file exists and is set-group-id.
[ -c $file ] True if file exists and is character special.
[ -d $file ] True if file exists and is a directory.
[ -e $file ] True if file exists.
[ -f $file ] True if file exists and is a regular file.
[ -g $file ] True if file exists and is set-group-id.
[ -k $file ] True if file has its ``sticky'' bit set.
[ -L $file ] True if file exists and is a symbolic link.
[ -p $file ] True if file exists and is a named pipe.
[ -r $file ] True if file exists and is readable.
[ -s $file ] True if file exists and has a size greater than zero.
[ -c $file ] True if file exists and is character special.
[ -d $file ] True if file exists and is a directory.
[ -e $file ] True if file exists.
[ -f $file ] True if file exists and is a regular file.
[ -g $file ] True if file exists and is set-group-id.
[ -k $file ] True if file has its ``sticky'' bit set.
[ -L $file ] True if file exists and is a symbolic link.
[ -p $file ] True if file exists and is a named pipe.
[ -r $file ] True if file exists and is readable.
[ -s $file ] True if file exists and has a size greater than zero.
[ -S $file ] True if file exists and is a socket.
[ -t $fd  ] True if fd is opened on a terminal.
[ -u $file ] True if file exists and its set-user-id bit is set.
[ -w $file ] True if file exists and is writable.
[ -x $file ] True if file exists and is executable.
[ -O $file ] True if file exists and is owned by the effective user id.
[ -G $file ] True if file exists and is owned by the effective group id.

Directory Size Lister/Sorter

Have you ever wondered which directories and trees take up all the diskspace? Questions like this come during pruning/archiving, backup, and numerous other activities. Make the following oneliner script (I call it dirsizes) to find out:

du -sm $(find $1 -type d -maxdepth 1 -xdev) | sort -g

The preceding shellscript prints every directory below the one called as an argument, together with its size, sorted with the largest at the bottom. We sort largest at bottom so there's no necessity to pipe it toless. Instead, you can see the largest 24 on the screen after the command.

If you find a large tree, but can't delete the whole thing, you can explore just that tree by using its directory as the argument, and you'll see all its subtrees and how much space they take.

But let's say you want to see ALL directories in the tree, instantly zeroing in on big diskspace directories. Make the following shellscript, which I call alldirsizes:

find $1 -type d  | xargs du -sm | sort -g

Both these scripts do more than just add filesizes. They take into account inodes, so they reveal the space that would be recovered if the directories were deleted.

Both of these scripts are most accurate when run as root, but they're pretty informative run as just a normal user.

CUPS Tips

X-Sender: slitt@207.171.0.150
X-Mailer: QUALCOMM Windows Eudora Light Version 3.0.6 (32)
Date: Fri, 24 Nov 2000 11:59:15 -0500
To: leaplist@lists.leap-cf.org
From: Steve Litt <Steve Litt's email address>
Subject: [LeapList] Cups tips
Reply-To: leaplist@lists.leap-cf.org
Sender: leaplist-admin@lists.leap-cf.org
X-Mailman-Version: 1.0rc2
List-Id: General Linux Discussion List for LEAP <leaplist.lists.leap-cf.org>
X-BeenThere: leaplist@lists.leap-cf.org

On my mandrake 72 I noticed that using lpr to print a text file was
printing too close to the left and cutting off half the first character.
This is a cups system.

So I looked at http://localhost:631, which is the cups equivalent of swat.
It pointed me to a cups manual, which noted that the lpr command can be
used to change margins:

lpr -o page-left=24 /etc/smb.conf

The preceding prints smb.conf with a left margin of 1/3 inch (24/72). There
are a smorgasbord of options for duplexing, characters per inch, page
ranges (and isn't that nice when a .ps or .pcl file jams in the middle),
and tons of other stuff. However, I couldn't make the brightness setting
work right, as when I made the text darker, the background on the last page
turned dark.

By the way, I'm sure there's some place where I can make the page-left
default 24 points, but I just haven't found it yet.

SteveT

Mouse: Fast and Accurate Mousing Under Linux

(Updated in 2019)

By default, the mouse under Linux is typically much too slow, requiring large hand movements to move the pointer. For some reason this is even more true of the excellent LXDE desktop environment. This is inconvenient, and although I'm a layman with regard to ergonomics, I personally fear those large hand movements put me at greater risk for repetitive motion injuries. Luckily, this problem is easy to fix.

Many people think the fix is to boost the acceleration. That makes the mouse fast enough, but requires you to move the mouse quickly to traverse large distances, then slowly to zero in on the exact target. With an overly large (like 5) acceleration, mousing resembles golf -- one or two drives followed by a couple of putts. Not good for productivity.

There used to be a special line you could put in the X config file to increase inches of mousepointer travel per inch of mouse travel, but that stopped working sometime in the early 00's.

The best current solution (maybe it should be called a wordaround) is to speed up the mouse hardware:

As far as acceleration, I like an acceleration value of 2. Here's the command to get it:

xset m 2 1

To get a 3 to 1 acceleration, which I think is too high, use this:

xset m 3 1

Recording, Playing and Converting sounds

First, make sure aumix is installed, and use it to set both the record and play volumes, and make sure the microphone is the record device and not muted. Don't use a GUI mixer -- they sometimes get it wrong.

To record a song from the microphone, just do this:

$ rec mysong.au

If you want to change the volume, use -v, which is a float where >1.0 amplifies, and <1.0 attenuates. Note our hearing is logrithmic.

$ rec -v2 mysong.au

To play it back, do this:

$ play mysong.au

To convert it to a .wav, do this:

$ sox mysong.au mysong.wav

Sox can also amplify, flanger, phaser, echo, and various other effects. See man sox.

Finding Who Has a File Open

How often do mounts and umounts fail because you can't determine what is using the device? How many times can you not eject a CD because something's got it open? How many times have you experienced a "file browser" that keeps a directory open even after you've navigated out of that directory and clicked the "refresh" button? Who's got this thing open??? Use the fuser program to find out:

[slitt@mydesk slitt]$ /sbin/fuser -mu /d
/d:                   1693(slitt)  1891c(slitt)  1894  1894c(slitt)
  1907  1907c(slitt)  1908  1908c(slitt)  1909  1909c(slitt)
  1910  1910c(slitt)  1912  1912c(slitt)  1913  1913c(slitt)
[slitt@mydesk slitt]$

The preceding command is great for finding who is holding open mounted devices. But sometimes you want to find who is holding open plain devices: For instance, when you want to restart ALSA and can't because something's using it. Do this:

slitt@mydesk:~$ fuser -au /dev/snd/controlC0 
/dev/snd/controlC0:  22596(slitt)
slitt@mydesk:~$
fuser -au /dev/snd/

You get the owner and the process ID. From there you can research using ps ax.

Be sure to look at the fuser man page for details on other info you can obtain. You can even kill all processes accessing a file, though I highly recommend against such a heavy handed move.

Modem Init Strings

Updated in 2019

NOTE:

It's tempting in some circles to laugh at the thought of modems in this modern world. But as long as the only low cost choice of some people in very rural areas is dialup, I'll keep this section intact.

Those who laugh at dialup would be more credible if they campaigned against state laws preventing counties and municipalities from serving Internet to their inhabitants, and campaign for laws treating at least 3Mb/s down and 0.5Mb/s up speed Internet as a utility and a right of everyone in the country.

Delay for Voicemail Phones

On some phone systems with voicemail, when there are unheard messages, the dialtone beeps several times. This can prevent the modem from connecting. If you have this problem, you can solve it with a simple modem init string addition.

On a Hayes compatible modem, and the following string onto the end of your modem init string:

S6=4

Register S6 determines the delay before checking for dialtone. By instituting a 4 second delay, by the time you check for a dialtone all the beeps will be gone. If 4 seconds isn't enough, try 10, and then trim it down from there.

The Modem Speaker

The following codes influence the modem speaker:

CodeFunction
M0Modem speaker always off
M1Modem speaker on during dial and handshake
M2Modem speaker on always
M3Modem speaker on during handshake
L codes, if present, should follow M codes
L1Modem speaker soft
L2Modem speaker moderate
L3Modem speaker loud

How to enable X across a network connection

  1. You might need to institute the ssh connection as ssh -x <remote_ip>
  2. export DISPLAY="<local_ip>:0"
  3. ;xhost +<remote_ip>

Turning Off OpenOffice Autocompletion

Of all the obnoxious "features" ever created, OpenOffice's "Word Autocompletion" is probably the worst. It makes the old "Microsoft Bob" look positively benign.

OpenOffice's autocompletion looks at your typing, and when a word appears to resemble another word in the document (or maybe elsewhere -- I'm not sure), it "helps" you by highlighting the whole word and adding letters to make it the resembled word. For a fast touch typist, it's distracting as the dickens.

So turn it off. From the OpenOffice menu, Tools->Autocorrect, and then uncheck the "Enable Word Completion" checkbox. That's it -- no more obnoxious word completion.

Copying Via SSH

If you want to copy an entire tree from one computer to another, sftp won't do it. Rsync can do it, but in certain cases rsync can consume too much RAM.  Assuming you're user slitt on the destination, and the tree belongs to user slitt on the source, here's a very easy to remember way to do it:

ssh slitt@source 'tar -cz /home/slitt/mytree' | tar -xzp

The p on the end of the extraction tar means "preserve permissions". The preceding places the home/slitt/mytree into the current directory, so you'll need to move mytree where you need it and delete the rest of the tree. To avoid that hassle and put mytree right into the current directory, use the -C option:

ssh slitt@source 'tar -C /home/slitt -cz mytree' | tar -xzp

Notice that everything within the singlequotes is performed on the remote computer, and everything after the last quote is performed on the local computer. The ssh program, when running a command, outputs the remote command's stdout on the local computer, so that data can be piped to local processes, which is what we're doing here.

The plot thickens if some files within the tar have different owners. In that case, the best thing to do is log into the local machine as root, go to the destination directory, and run it with the --same-owner argument on the extraction tar:

ssh slitt@source 'tar -C /home/slitt -cz mytree' | tar -xzp --same-owner

In my opinion, unless space is too tight to maintain both the .tgz and the extracted tree on the destination computer, this is better done as a three stage process:

ssh slitt@source 'tar -C /home/slitt -cz mytree' > /spare_directory/mytree.tgz
tar -tzp --same-owner -f /spare_directory/mytree.tgz
tar -xzp --same-owner -f /spare_directory/mytree.tgz

The first command creates a tarball, on the local computer, from the tree on the remote computer. The second command checks what's in the tarball, so if there's something wrong you can quit rather than possibly overwriting something valuable. The third command extracts the tarball to the current directory. Once again, the only real disadvantage of this is that you must have room for both the tarball and the extracted tree.

Running Terminals With Specific Fonts

Much time has passed since this tip was written, during which the FreeType library came into being, for the most part eclipsing the old way with its fonts.alias files and xfontsel font filename determiner. The new FreeType way, with its fc-list command replacing the function of the old xfontsel, is preferable, in my opinion. Nevertheless, as of 2/3/2018, this section still describes the old way, along with the superior new way.

The Old Way

This works for xterm, rxvt and urxvt, and probably works for some others. To specify a normal font (as opposed to a font used for bold), you run xterm with the -fn option:

rxvt -fn font_alias

The only trouble is, how do you find the font alias? That's contained in a file called fonts.alias. You find that file with locate command:

locate fonts.alias

When you look inside that file, each line has an alias followed by a space followed by a complete file specification, as shown in the following example from my computer:

lucidasanstypewriter-12 -b&h-lucidatypewriter-medium-r-normal-sans-12-120-75-75-m-70-iso8859-1

So in the preceding, the alias is lucidasanstypewriter-12. So your rxvt command would be as follows for this font:

rxvt -fn lucidasanstypewriter-12

Note:

The font for xterm can also be set within ~/.Xdefaults, but that's beyond the scope of this section.

The New Way

Around the turn of the century, Windows and Mac had much clearer and more readable fonts than Linux. During the last decade and a half (2003-2018) Linux fonts have caught up, thanks to FreeType and its Truetype fonts. These fonts are listed and specified differently than what came before. To list all FreeType fonts, perform the following:

fc-list | less

To view most of the fixed fonts, perform the following command:

fc-list | grep -i -e fixed -e mono -e typewriter | less

Terminal Command Line Font Specification Examples

The following are some example command line specification examples:

Telnetting to an SMTP Server

The following is an example of plain text username and password on port 26. The base64 is in plain text, and is easily converted back to the exact username and password. Note that at the end it bombs with an administrative prohibition, but it authenticated just fine.

This is how you test a username and password, and port number. First use perl to get your base64 username and password so you can paste them into prompts:

slitt@mydesk:~$ perl -MMIME::Base64 -e 'print encode_base64("myname\@mydomain.com")'
bXluYW1lQG15ZG9tYWluLmNvbQ==
slitt@mydesk:~$ perl -MMIME::Base64 -e 'print encode_base64("mypassword")'     
bXlwYXNzd29yZA==
slitt@mydesk:~$

I'm going to use on port 26 as per the webhost.

slitt@mydesk:~$ telnet mail.myisp.com 26
Trying 69.189.108.200...
Connected to myisp.com.
Escape character is '^]'.
220-mail2.myisp.com ESMTP Exim 4.76 #1 Wed, 11 Jan 2012 03:10:32 -0700
220-We do not authorize the use of this system to transport unsolicited,
220 and/or bulk e-mail.
ehlo
250-mail2.myisp.com Hello  [97.100.37.206]
250-SIZE 52428800 250-PIPELINING 250-AUTH PLAIN LOGIN
250-STARTTLS 250 HELP auth login 334 VXNlcm5hbWU6 bXluYW1lQG15ZG9tYWluLmNvbQ== 334 UGFzc3dvcmQ6
bXlwYXNzd29yZA== 235 Authentication succeeded
mail from: myusername@mydomain.com 250 OK
rcpt to: myusername@mydomain.com 250 Accepted data 354 Enter message, ending with "." on a line by itself Here I stand. . 550 Administrative prohibition

Xchat: Globally Getting Rid of Join/Part messages

The following irc command gets rid of Join/Part messages on all channels, relieving you of the need to set it on each channel tab:

/set irc_conf_mode 1

This can be put in $HOME/.xchat2/xchat.conf:

irc_conf_mode = 1
There's probably already a value for irc_conf_mode in the config file, so be sure to find it and change its value -- don't put in a second key.

Finding All Info About All Partitions

Here's how you find out everything you need to know about every partition: Device name, uuid, label, and mount point (if any):

lsblk -o NAME,LABEL,UUID,MOUNTPOINT

Do that command, and you'll know everything about every partition.

Single Tree Installation of Python Programs

Single tree installations are trivial to install: Just a recursive copy. Trivial to back up for the same reason. Trivial to transfer to another computer for the same reason. Few dependencies, easy deployment on a wide variety of platforms.

The challenge is that the program can be called from anywhere in on the computer, but it must "know" its anchor directory. Assuming the executable is in the anchor directory and not below it, this is pretty easy, simply by assigning variable targetdir to the value of arg0, doing the proper stuff so it always ends with exactly one slash. Once you have the anchordir directory, you can have your way with the whole tree by appending directories as necessary to locate all components within the tree. Here's how to do it in Python:

#!/usr/bin/python import sys import re import os anchordir = re.sub('/[^/]*$', '/', sys.argv[0]) if anchordir == './': anchordir = re.sub('/*$', '/', os.getcwd() + '/') datadir = anchordir + 'data/' templatedir = anchordir + 'templates/' print('Heres anchordir : {}'.format(anchordir)) print('Heres arg0 : {}'.format(sys.argv[0])) print('Heres datadir : {}'.format(datadir)) print('Heres templatedir : {}'.format(templatedir)) print('Armed with anchordir, you can have your way with the whole tree.')

Cooler still, this technique works even if the python file isn't permissioned executable, and instead is invoked like this:

python /home/slitt/myprograms/myapp/do_my_app.py

Using the find Command, -mtime and -exec

If you're like me, the xargs command spooks you to no end. xargs is unpredictable and often dangerous unless you know it intimately.

The good news is, for all those times you were tempted to pipe find into xargs, you can use the find command's -exec option to do about the same thing. But you need to know the syntax:

find -type d -exec ls -ldF {} +

The preceding command finds all directories in the tree (-type d), and pipes them into an ls commands that doesn't recurse. Here's the explanation:

You can also use the find command to find files of a certain age. Files have three different times associated with them:

The only use I can think of for access time is criminal forensics. And even then, many filesystems are mounted noatime, removing access time as a useful measure. Access time is represented by -atime in the find command.

Creation sets both the creation time (-ctime) and the modification time (-mtime). In practice, I've had little success using -ctime in the find command, so I won't discuss it further.

Modification time is updated when a file is first created, and every time it's modified. I've found -mtime to be reliable, reproducible, and useful. It's March 28 today. Let's say I'm looking for a file I created in February. I might do something like this:

find -type f -mtime +25 -mtime -62  -exec ls -l {} + |  less

The reason I widened the margins on both the younger and older ends is I didn't take the time to get it exact. I'd rather see a few extraneous entries than spend a lot of time remembering the exact meaning of the plus and minus, which can be varied by certain other command options. If you really must have it exact, you'll need a lot more reading of the find man page, some experimentation, and know what to do with fractional days.

nmap, Find all IP addresses on the subnet

To quickly find all IP addresses on the subnet, do the following as a normal user:

nmap -sn -n 192.168.100.0/24 | grep ^N

Obviously, you'll need to change the address and netmask to suit your particular subnet.

If you want operating system information and can run the command as root, use the following command:

nmap -sT -O -n 192.168.100.0/24 | less

Adding a Line to Sudoers

The following is a typical line added to the sudoers file with the visudo command:

slitt  ALL=(root:ALL)  NOPASSWD: /usr/bin/mount

In the preceding, the slitt is the username that is being given these privileges. The first ALL means slitt can run the command from any computer, not just localhost. (root:ALL) is a username:grop pair that means that the command will run as user root and it can run as all groups, which I guess means any group, which, well, I don't know what that means.

The NOPASSWD: provision (the colon is a must) says that the user won't be required to type in a password. Use this on desktop computers for commands that are pretty much harmless in a desktop setting. Last but not least is the command all of this applies to. You can have a comma-separated list here at the end, but I'd recommend this only if the commands are related and have the exact same permission situations.

The line should always be in the order described above. The following is a repetition:

username hostlist=(runas_user:runas_group) NOPASSWD: command_list

If you want to require a password, remvoe NOPASSWD:.

Unhelpful Statefulness

sudo has various stateful properties that normally help but can appear like an intermittent during troubleshooting. Any changes performed in visudo require you to exit visudo before they take effect. When testing as a normal user, issue a sudo -K, every time, before running the test, to clear cache. My experimentation tells me there's no reason to log out and log back in before each test.

Void Linux Boot Without Framebuffer

Gotta love these programmers with 20/10 vision who create software useable only by those with 20/10 vision. Hey, if you can't read 6 point, gray on black writing, you have no business using the software!

And then there are the framebuffers that change the video mode, so your video projector or KVM-attached monitor must keep retrying, and you miss half the boot. If you ever find yourself nostalgic about the DEC PDP-11's no-style, all characters, 80x24 character output, read on...

In Void Linux (as of 9/11/2016), booting without a framebuffer (and therefore with 80 char x 24char white output) is as simple as adding nomodeset in the right place, and then recompiling grub. Specifically...

  1. vim /etc/default/grub
  2. Find line GRUB_CMDLINE_LINUX_DEFAULT="loglevel=4"
  3. Change to GRUB_CMDLINE_LINUX_DEFAULT="loglevel=4 nomodeset"
  4. Save the file.
  5. update-grub
  6. Reboot, and enjoy your large font, resolveable by any projector screen.

NOTE: The steps in this section won't work in Qemu, at least with the default gfx card.

Starting LXQt From startx

The LXQt window manager is important because it supersedes LXDE, currently (1/2017) the most stable, dependable and intuitive window manager. LXQt is easy to run from a display manager like lxdm, xdm or lightdm, but it's difficult to run from startx and most distros have zero documentation on doing so.

The trick is to imitate the process tree bestowed by the correctly operating LXQt started from a display manager, using the ps axjf command. The following is the subtree under the lxdm process, as displayed in Void Linux running under the lxdm display manager:

 \_ runsv lxdm
      \_ /usr/bin/lxdm-binary
          \_ /usr/libexec/Xorg -background none :0 vt07 -nolisten tcp -novtswitch -auth /var/run/lxdm/lxdm-:0.auth
          \_ /usr/libexec/lxdm-session
              \_ lxqt-session
                  \_ openbox --config-file /home/slitt/.config/openbox/lxqt-rc.xml
                  \_ pcmanfm-qt --desktop --profile=lxqt
                  \_ lxqt-globalkeysd
                  \_ lxqt-notificationd
                  \_ lxqt-panel
                  \_ lxqt-policykit-agent
                  \_ lxqt-runner
                  \_ lxqt-powermanagement

The takeaway from the preceding tree is that openbox, pcmanfm-qt, and several LXQt utilities including its panel run as CHILDREN of lxqt-session. If you can get that to happen from startx, it works almost identically. The following shellscript, $HOME/lxqt-session.sh makes it happen:

# Open lxqt-session's children
/usr/bin/openbox --config-file /home/slitt/.config/openbox/lxqt-rc.xml  &
/usr/bin/pcmanfm-qt --desktop --profile=lxqt  &
/usr/bin/lxqt-globalkeysd  &
/usr/bin/lxqt-notificationd  &
/usr/bin/lxqt-panel  &
/usr/bin/lxqt-policykit-agent  &
/usr/bin/lxqt-runner  &
/usr/bin/lxqt-powermanagement  &

#Make this shellscript become lxqt-session
exec /usr/bin/lxqt-session

The preceding shellscript makes the necessary children of lxqt-session to be children of the shellscript, with the same arguments, in the same order. The final line makes the shellscript process into an lxqt-session process, so the parent child relationships are identical.

The preceding shellscript makes the necessary children of lxqt-session to be children of the shellscript, with the same arguments, in the same order. The final line makes the shellscript process into an lxqt-session process, so the parent child relationships are identical.

Chmod $HOME/lxqt-session.sh executable by all and change $HOME/.xinitrc to the following:

#!/bin/sh
exec $HOME/lxqt-session.sh

With these tasks completed, when you run startx, you get a working, full featured LXQt.

Remember, the key idea here is that if LXQt works from a display manager in a boot-to-GUI situation, you can make it work from startx by writing a shellscript to reproduce the process hierarchy below lxdm-session in the boot-to-GUI situation.

Toggling the Touchpad On and Off

As of 6/4/2019, every solution ever shown in this section is superceded by the Touchpad Toggler For Linux document.

Inkscape: Toggling Stroke Width and Other Properties Changes on Resizeing Objects

Imagine an Inkscape 1 inch by 1 inch square with a 0.1 inch red stroke. Now, in selection mode, you grow it to 3 inches by 3 inches, either by dragging a corner or by tripling the height and width in the icon bar across the top. One of two things will happen:

  1. The stroke width triples right along with the height and width
  2. The stroke width stays at 0.1 inches

You can toggle which way it acts. Observe, when the selection tool (the one with the arrow, in the upper left) is chosen, right after the measurements and the unit dropdown the icon bar contains four similar looking icons, as shown in the following graphic:

Icon for stroke change mode

In the preceding graphic, see the four icons on the right. The leftmost one is depressed. That's the one that controls whether the stroke grows with the object. If depressed, the stroke grows with the object. If not depressed, the stroke stays as-is regardless of resizing of the object.

With each of the four icons, you can see their purpose by hovering over them and reading the tool tip. From left to right, their purposes are:

REMEMBER:

These icons are available only when you've enabled the selection tool (Selection tool clickable icon), which is shown depressed in the following context screenshot:

Selection tool in context with controls around it

Adding command history and editing (readline) to any program

Many command interface programs, such as tclsh, dash or guile, have no arrow based command line history and editor of their own. You can add arrow based command history and editing by running them from the rlwrap program, like the following:

rlwrap guile

Various "Exists" Methods in Python3

A question often needing an answer in Python is "does variable z exist? It sounds like a simple question, but it's not, because it could mean several different situations, each of which need to be treated differently.

Checking that a Variable Has Been Declared

This cannot be done by normal Python means. If a variable's name hasn't been used on the left side of an equal sign, it's undefined and cannot be checked. If, for some reason, you simply must check if a variable name has been declared, the following is the only way I know:

#myvarname = 3
try:
    myvarname is None
except:
    myvarname = None
print(myvarname)

In the preceding code, if you uncomment the assignment of 3 to myvarname, the number 3 will be printed instead of "None".

I can't think of a situation requiring this in the absence of sloppy programming.

Did a function return a value?

Here's where you use Python's is keyword. Observe the following, which prints "True":

def varmaker():
    pass
myvar =  varmaker()
print(myvar is None)

In the preceding, myvar did appear on the left side of an equal sign, so asking if its value is None is a valid question.

Does a dictionary have a specific key?

You can check whether a dictionary has a specific key as with the following simple function called getval():

def getval(d, k):
    if k in d:
        return d[k]
    return None

print(getval(mydict, 'mykey'))
print(getval(mydict, 'mykey2'))
print(getval(mydict, 'nokey'))

mydict = {}
print('............')

print(getval(mydict, 'mykey'))
print(getval(mydict, 'mykey2'))
print(getval(mydict, 'nokey'))

The preceding code exercises the getval() function. Please keep in mind that the preceding does not distinguish between a nonexistent key and a key that exists but has a value of None.

Assign dict element to a var only if not null

def getval2(d, k, curr):
    if k in d:
        return d[k]
    return curr

name = 'Steve'
name = getval2(mydict, mykey, name)

The preceding leaves the variable alone if the key doesn't exist, but if the key exists, even if the key's value is None, that value is assigned. This is probably what you want, but if you want the original variable's value to be left alone if the dict key's value is None, then code it as follows:

def getval3(d, k, curr):
    if k in d and d[k] is not None:
        return d[k]
    return curr

Does a *list* have a specific value?

The easiest way is to use in, similar to a dict:

if 'Corvette' in mylist:
	act_accordingly()

The preceding works all the time, in every circumstance, and it's easy and memorable. However, in huge lists it can be slow. Another method is to create a set based on the list, and check the set:

myset = set(mylist)
if 'Corvette' in mylist:
	act_accordingly()

Neither of the preceding give you the index of the sought value. If you need that, and the list is large enough to be slow for both finding the right index and using the in verb, then the following code kills two birds with one stone:

try:
	myindex = mylist.index('Corvette')
except ValueError:
	# assign myindex -1 or some such, or
	pass

Phil Barnett's Quote About Just Getting It Fixed

When criticized about a fix he made to his local KVM, Phil Barnett commented in his 3/27/2014 post to LEAP's user mailing list:

While it would be nice to spend days figuring it out, I spent minutes and got past it.

How to Fix Boned Fonts in Early June 2021 Firefox Update

NOTE: As of October 2021, Firefox became so unmanageable in so many ways that I quit using it. I now use Chromium for websites demanding the kitchen sink, and slimmer browsers where I can.

On 6/7/2021 using Void Linux, after a new Firefox update, Firefox displayed Facebook fonts, some Github fonts, and probably fonts on other websites in an unadjustable tiny font (like 5 point). I'm betting this is a Firefox error. One solution would be to switch browsers, but they all have their problems. This section shows a workaround script, and an un-workaround script in case the workaround does what workarounds do and causes unpleasant side effects. This information is based on information from https://docs.voidlinux.org/config/graphical-session/fonts.html. It should work on Void Linux, and something similar might work on other distros.

The Workaround Shellscript

The following workaround Shellscript I call firefox_font_workaround.sh, which must be run as user root, disables bitmap fonts on your computer:

#!/bin/sh
if test -f /etc/fonts/conf.d/70-no-bitmaps.conf; then
   echo I REFUSE TO PROCEED >&2
   echo file /etc/fonts/conf.d/70-no-bitmaps.conf already exists >&2
   echo If appropriate, delete it and rerun this workaround >&2
   exit 1
fi
ln -s /usr/share/fontconfig/conf.avail/70-no-bitmaps.conf /etc/fonts/conf.d/
xbps-reconfigure -f fontconfig
echo "\n\n\n\n"
fc-conflist
echo "\nBitmap fonts now disabled."
echo "Fonts on Facebook, Github and"
echo "other affected sites should now"
echo "work correctly in Firefox.\n"

The UnWorkaround Shellscript

The following shellscript I call firefox_font_unworkaround.sh, which must be run as user root, undoes the workaround:

#!/bin/sh
rm /etc/fonts/conf.d/70-no-bitmaps.conf
xbps-reconfigure -f fontconfig
echo "\nBitmap fonts now re-enabled."
echo "Check fonts on Facebook, Github and"
echo "other affected sites in Firefox.\n"

Using the Scripts

Run these shellscripts as user root. Use the workaround script to disable bitmap fonts in order to work around the Firefox font problem on certain websites. If the workaround causes problems on other work, remove the workaround with the unworkaround script. Also, as new Firefox updates come in, use the unworkaround script to see if the problem has been fixed, and if not, re-use the workaround script.

Sakura Accelerator Key Bit Numbers

Sakura's config file reveals only the main key you press, not the Alt, Shift, Ctrl, Win keys you press with it. The key(s) you press with it are called the "accelerator" keys, and are defined by or'ing several numbers. The numbers follow:

So for instance, the accelerator key for all color changes is 5, with the keys being F1 thru F6. 5 is 1 + 4, so the accelerator key is Shift+Ctrl. To change to color choice 3, press Shift+Ctrl+F3. To change to color scheme 4, Shift+Ctrl+F4.

Cool Use of Sed: Finding Qemu Network Devices

Check out the following cool use of sed:

qemu-system-x86_64 -device help | sed -ne '/^Network devices:/,//p' | sed -e '/^$/q'

The preceding command gives you a list of every possible qemu network device.

Steve Litt's Surefire Way to Get Answers

It's frustrating. You need info. You do all the RTFM and web searching and still can't find the info. So you ask on a relevant mailing list, and you get nothing but silence. And you know darn well some of these people know the answer, but they can't be bothered. How do you get them to answer? Use Steve Litt's Surefire Way to Get Answers! Here it is, as a process:

This method almost always works. I leave it to you, the reader, to decide what this says about human behavior.

Simple Xargs Substitute

This section is not yet developed.

Sorting a Directory Tree by Date

Sorting a whole tree by date is both handy and difficult. The following command does it for you:

time tree -QDinf --timefmt "%Y-%m-%d__%H-%M-%S" . | sort

The preceding command gives you a list of every possible qemu network device. The following is how it works:

This command gives you the basic information, and takes care of the difficult task of sorting an entire tree by date. If you have additional requirements, these can be done by piping the results to another command.

HTML/CSS/JS Quickhacks

This article has its own page at http://troubleshooters.com/web/html_quickhacks.htm

How To Spell Check in VSCode

First you install the VSCode spell checker as follows:

  1. Click Help on the menu
  2. Click "Show all commands"
  3. In the provided field, type "Extensions: Install Extensions"
  4. In the supplied field, type in code-spell-checker
  5. Choose "Code Spell Checker" from the dropdown list
  6. Click the install button
  7. Save all open documents
  8. Close VSCode
  9. Reopen VSCode

Once VSCode's spell checker is installed, it automatically squiggly underlines words it doesn't recognize. As you type, it squiggly underlines unrecognizeable words you typed. If you hover over the misspelling, you get an opportunity to see suggested words. Or you can right click to ignore, subtitute, or add the word to the dictionary.

How To Allocate 2d Arrays In C

If you want to allocate a 2d array that can be used as a 2d array, for instance, my2dArray[4][3], the int **my2dArray must be allocated in a specific way, dimension by dimension. Trying to allocate it other ways, such as allocating sufficient heap space in one allocation call, puts you on the highway to heartache if you intend to use it as a 2 dimensional array. Here are a few rules of the road for 2d array allocation:

Here's a C file demonstrating the dimension by dimension method.

The following is a simple shellscript to quickly compile and run (with Valgrind) the allocating_2d_arrays.c program:

#!/bin/sh
echo "\n\n\n\n\n\n"
if gcc -Wall -g allocating_2d_arrays.c; then
   valgrind ./a.out
else
   echo "Compile failed"
fi  

One final thought: I suspect that this layer by layer allocating is universally true, no matter what sequence of structs and arrays you need to allocate.

The Right Way to Handle Interrupts in C

Interrupt handling is C is a problem because a relatively few functions are safe inside interrupt handlers (the buzzword is "async safe", which is not the same as "thread safe"). Specifically, printf() and sprintf() aren't allowed in interrupt handlers. This is ugly because interrupts are how you go asyncronous, and you sure don't want to do polling to see when a file is ready or something like that. Fortunately, there's a safe way to accomplish almost the same thing.

With the safe way, the only thing done by the interrupt handler is to set a global static int to the interrupt number. Perform the proper signal() calls in order to refer all handled signals to the interrupt handler that does nothing but set the global static int to the value of the interrupt inside. Right after the signal() calls, run a loop with pause() as the first statement. The pause() function waits (blocks) until a handled interrupt is received. Below the pause() call, you use the value of the global static int to determine what action to take. The following is a simple example:

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<sys/select.h>

// interruptFlag must be global
// It must also be static but I don't know why.
static int interruptFlag = 0; 

void interruptHandler(int sig) {
    interruptFlag = sig;
}
  
int main() {
    (void) signal(SIGUSR1, interruptHandler);
    (void) signal(SIGUSR2, interruptHandler);
    while(1){
        printf("Waiting for interruptHandler() to change interruptFlag...\n");
        pause();
        if (interruptFlag)
          printf("Interrupt=%d detected\n", interruptFlag);
        interruptFlag = 0;
    }
}

This solution is simple but it's not a panacea, because the program can't do its other business while waiting for an interrupt. It's not truly asyncronous. But it's perfect for a pair of programs in which program1 writes a file, then sends a SIGUSR1 to program2 so program2 can instantly handle that file, write a file of its own, and signal program1 to continue.

We've all done program pairs where program1 produces files and program2 polls to find new files and handles them as found. This is just fine if you can afford a second between each handling of a file. But when new files are created every few milliseconds, such polling would be tie up the CPU.

This technique can go both ways, where program1 interrupts program2 to do its work, and program2 interrupts program1 when program2 has completed its work so that program1 is free to take over.

The technique described here is most useful when iterations in program2 are much quicker than those in program1, so that not much efficiency is lost when program 2 needs to wait for program1.

The use case that prompted me to explore such interrupting was a Python program sending lots of phrases, one at a time, to a C program that handled the phrases and let the Python program know when the handled phrase was ready. Sure, I could have simply had the Python program spawn the C program for each phrase, but I didn't want the C program's startup and teardown time added to each Python iteration, and I didn't want the C program to have to read the 100K hash table file for each Python iteration.

The Right Way to Handle Interrupts in Python

This is the Python equivalent of the The Right Way to Handle Interrupts in C section immediately preceding this section. It's almost the same algorithm, except instead of updating a global variable, the interrupt handler sets a global instance of a class. For some reason, in Python if the interrupt handler simply updates a variable, the variable is zero outside the interrupt handler. By giving the Python program interrupt handling capability as well as the C program, they can play ping pong sending files back and forth, with each getting an alert when the next file is ready.

The code to handle interrupts in Python follows:

#!/usr/bin/python3
import signal
import sys

class FlagObject:
    def __init__(self):
        self.flag=0;
    def setFlag(self, flag):
        self.flag=flag
    def getFlag(self):
        return self.flag

flagObject=FlagObject(); # Global instance


def interruptHandler(sig, stackFrame):
    flagObject.setFlag(sig)

signal.signal(signal.SIGUSR1, interruptHandler);
signal.signal(signal.SIGUSR2, interruptHandler);
while(True):
    print("Waiting for interrupt....")
    signal.pause()
    if flagObject.getFlag != 0:
       print("Interrupted by signal {}.\n".format(
            flagObject.getFlag()))
    flagObject.setFlag(0)  

Using an amplification of the preceding code, your Python program and C program can play ping-pong with files created by Python and modified by C, without polling on either end, and without either needing to be rerun.

How to edit the URL in Qutebrowser

Everyone knows Qutebrowser is a great, reliable, non-bloated, keyboard friendly and user friendly browser. And everyone knows that being able to edit the current URL is a must in order to have a fast workflow. The following two key combos accomplish this in Qutebrowser:

In either case, you're presented with the current URL with the cursor at the end of the line. You can use the backspace, left and right arrow keys, delete key, and letters, numbers and symbols from the keyboard to modify the URL. This is a productivity booster when you need a URL very similar to the current one.

How to Configure Qutebrowser

Finding Your Configuration File Location

To find the configuration directory, run Qutebrowser, run the :version command, look in the "Paths:" area, and record the value of "config:". This is the directory that should hold your config.py (if there is one) and your autoconfig.yml (if there is one) files, as well as any other Qutebrowser config files you may have.

Example config.py File

See textfiles/config.py.txt for an example config.py. The example file has comments that guide you on syntax for this file.

The preceding subsection tells you how to find the directory in which to put it. Be sure you don't already have a config.py so you don't overwrite it.

Researching Config Options

Just open qute://help/settings.html to see all your config options. It's a good idea to browse them to give yourself an idea of all the things Qutebrowser can do.

Getting Help

qute://settings
Here you can get info on all the possible settings and see their current value. I'd highly recommend that rather than trying to alter settings here, you alter them in config.py.
:version
This shows you version and compile information, including paths.
qute://help
Various help topics.
qute://warning/sessions
Information about sessions, in regard to your version of Qt and Qutebrowser's current development.

How To Add An Alias IP Address

You might find yourself needing an IP address on your computer that isn't used by anything else. You accomplish this using an alias IP address. Your alias IP address must be connected to to a specific device: Wire Ethernet, Wifi, a bridge or whatever.

As an example, imagine a computer whose wired Ethernet is named enp40s0 and assigned IP address 192.168.0.2. To create an alias on enp40s0 with IP address 192.168.0.105, perform the following command as user root:

ip addr add 192.168.0.105 dev enp40s0

How To Put a Viewport in a Web Page

Any modern, quality web page requires a viewport declaration in its head section. The following is the usual viewport declaration:

<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

Brother Printers on Void Linux

Brother printers are sooooooooo Linux friendly, they even give you downloadable drivers. If you use the RPM or APT package manager system, that is. If you use Void's superior XBPS packaging system, you're just not important to Brother.

So the Void project helps you out. Install the following packages:

Look at web page https://docs.voidlinux.org/config/print/index.html and search for the word "brother" (without the quotes).

Where you go from here depends on whether your printer has network connectivity or not...

Setting up a network printer

  1. Run Void's superior system-config-printer program.
  2. Click the Add button toward the upper left.
  3. In the left pane, highlight "Enter URI".
  4. In the right pane's "Enter device URI" field, input ipp://printer_ip_address/ipp, where "printer_ip_address" is the IP address of the printer you're configuring.
  5. In the list of printers, select "Brother" and click the Forward button.
  6. In the list of drivers, choose the one matching or closest to your printer. Be sure if your printer model starts with "MFC" you choose a driver beginning with "MFC". Same for "HL" or "DCP". Also be sure the driver name contains "N" for "network" or "W" for "wireless". This step could involve some trial and error if your exact printer isn't listed. When done choosing, click the forward button.
  7. In the "short name for this printer" field either leave it alone or put in something more descriptive like "lp_duplex" or "lp_toner_saver". This short name becomes the printer queue's device name. Do yourself a favor and put no spaces or punctuation other than underscores and maybe hyphens in this short name.
  8. In the "description" field, put something you'll recognize, either the same as your short name or something like "John Smith's Computer".
  9. You can leave the location field blank or put in something like "John Smith's office in building 24".
  10. Click the Apply button.
  11. When asked whether to print a test page, click the "print test page" button.
  12. If a test page isn't printed, go back and change the driver choice by clicking the "Change..." button to the right of the "Make and model" field. Continue your trial and error until one prints a test page.

Congratulations, you've installed your print queue. Now you need to set its settings. Now perform the following tasks:

  1. From the system-config-printer program, right click the printer you just made, select "properties" to access a dialog box.
  2. On the dialog box, select "Printer options" from the left hand list and select the desired/proper media size, resolution, toner save mode, duplex if desired/proper, and other things listed.
  3. When done, click the "Apply" button.
  4. Select "Job options" from the left hand list, and change anything you consider wrong.
  5. Click OK. Your print queue should now be ready for action. Print some jobs and make sure it prints right. Otherwise you'll need to experiment.

Setting up a USB printer

I don't know how to do this yet.

Copying Many Emails Between IMAP Servers

See Transferring lots of messages between IMAP accounts

Using Spaces Instead of Tabs in Vim

Sometimes you want a tab to be a tab character, and sometimes, such as Python or Ada source code, you want a tab to insert a number of spaces. When you want to insert a number of spaces, use the following Vim modeline inside a comment in your program:

WARNING!

There MUST be at least one space before the word vim:!

tmux Bootstrapping Info (not yet complete)

tmux is a great program with so many keyboard-driven commands that you can't self-learn it without a starting point. This section gives you that starting point.

The first thing you need to learn is what key-combo is used for the command prefix. By default this key combo is Ctrl+b, but that's such a nasty hand-stretch that it's often changed by the admin. To find the command prefix key combo, you need to look in the config file chain, which is described in the tmux man page. As a starting point for the discussion of the config file(s), the following is the content of my /etc/tmux.conf, which in my case is the only config file and is not overridden by any other files:

# Start at window #1 instead of #0
set -g base-index 8

# Make the 0 key refer to window #10 not window #0
bind 0 select-window -t 10

# swap ^J and ^B so tmux uses screen's keys
set-option -g prefix C-j
unbind-key C-b
bind-key C-j send-prefix

# Set scroll in vi mode
setw -g mode-keys vi

# Enable mouse copy on CLI terms
set -g mouse on

The preceding makes the command prefix Ctrl+j and also enables vi mode scrolling and Command Line Interface (CLI) copying via the mouse. For the rest of this section, keep in mind that Ctrl+j is the command prefix keyboard combo.

The one absolutely necessary key combo is the one to list all other key combos:

Ctrl+j ?

That's Ctrl+j followed by the question mark (upper case forward slash on most American keyboards. With this key combo you can look up any and all keyboard combos, adapted to whatever configuration is in effect. The remainder of this section introduces a few often used key combos so you don't need to look them up:


[ Training | Troubleshooters.Com | Email Steve Litt ]