Troubleshooters.Com and T.C Linux Library Present
Linux Quick Hacks
Copyright (C) 2000-2022 by Steve Litt, All rights reserved. Material provided as-is, use at your own risk.
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.
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 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).
Here's a script to test for a file's existence:
if [ -e $file ]; then
./myUtil $file
fi
TEST | MEANING |
[ -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. |
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.
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
(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
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.
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.
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.
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 following codes influence the modem speaker:
Code | Function |
M0 | Modem speaker always off |
M1 | Modem speaker on during dial and handshake |
M2 | Modem speaker on always |
M3 | Modem speaker on during handshake |
L codes, if present, should follow M codes | |
L1 | Modem speaker soft |
L2 | Modem speaker moderate |
L3 | Modem speaker loud |
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.
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.
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.
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.
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
The following are some example command line specification examples:
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
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 = 1There'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.
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 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:
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
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.
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
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:.
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.
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...
NOTE: The steps in this section won't work in Qemu, at least with the default gfx card.
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.
As of 6/4/2019, every solution ever shown in this section is superceded by the Touchpad Toggler For Linux document.
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:
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:
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 (), which is shown depressed in the following context screenshot:
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
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.
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.
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.
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.
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
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
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.
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 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 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"
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'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.
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.
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.
This section is not yet developed.
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.
This article has its own page at http://troubleshooters.com/web/html_quickhacks.htm
First you install the VSCode spell checker as follows:
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.
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.
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.
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.
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:
go
: Enables you to edit the URL in the current tab.gO
: Opens a new tab with the current URL, and enables
you to edit that URL.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.
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.
config.py
FileSee 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.
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.
config.py
.:version
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
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 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...
Congratulations, you've installed your print queue. Now you need to set its settings. Now perform the following tasks:
I don't know how to do this yet.
See Transferring lots of messages between IMAP accounts
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:
-- vim:ts=3:sw=3:expandtab
for Ada.# vim:ts=3:sw=3:expandtab
for Python.// vim:ts=3:sw=3:expandtab
for C./* vim:ts=3:sw=3:expandtab */
for C.(* vim:ts=3:sw=3:expandtab *)
for Pascal.// vim:ts=3:sw=3:expandtab
for Javascript./* vim:ts=3:sw=3:expandtab */
for Javascript.WARNING!
There MUST be at least one space before
the word vim:
!
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: