Skip to content

Launching Programs: dmenu_run and process groups?

Update 06-May-2012: I’ve been reading the mailing list to see if this has come up before, and there is a lengthy thread on improving dmenu_run. From what I can tell, the examples for improvement all had some sort of  “exec” call in them (but did not seem the focus of the discussion).  Looking through the revisions, it looks like dmenu_run did use ‘exec’ but called it on a shell, but this was changed for the purpose of “disowning the child shell.” The only thing I can think is perhaps this is due to a difference in how dmenu_run is invoked…

I just moved back to i3 from wmii, and after using it for a bit, I noticed that after launching programs with dmenu_run that they all were running under zsh (my SHELL) in pstree.

I remember wmii would launch the program as it’s own process. I like zsh in interactive uses, but it is a bit heavy wait to be used for just spawning processes. Luckily, dmenu_run uses ${SHELL} for launching, so I just made my keybinding launch “SHELL=dash dmen_run …” instead of plain “dmenu_run …” This worked nicely as it used dash to launch the program and took up much less memory.

But then, I thought why would dmenu_run launch programs this way? Wouldn’t it be a better idea to launch an application in it’s own group, say with the ‘exec’ function? The only reason I could think not to was the ability to use dmenu_run as a kind-of “one-off” shell. I’m not an expert on ‘exec’, but I was testing it out, and it still gave the same functionality. So, I made a modified dmenu_run called dmenu_exec, that just prepends “exec” to whatever it pipes to the shell. So far, it seems to be working as expected, and still allows me to use dmenu_run as a “one-off” shell.  And because I’m still piping this to a shell to run, I left the SHELL=dash line in my keybinding.

From what I understand about process groups, this seems to be a better way to launch programs, but as it isn’t what the dmenu developers did (and they seem like a pretty smart bunch), I wonder if there is something I’m missing. I’m using this for now, but any comments would be appreciated.

#!/bin/sh
cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
if [ -d "$cachedir" ]; then
    cache=$cachedir/dmenu_run
else
    cache=$HOME/.dmenu_cache # if no xdg dir, fall back to dotfile in ~
fi
(
    IFS=:
    if stest -dqr -n "$cache" $PATH; then
        stest -flx $PATH | sort -u | tee "$cache" | dmenu "$@"
    else
        echo "exec $(dmenu "$@" < "$cache")"
    fi
) | ${SHELL:-"/bin/sh"} &

Immersion

Since getting laid off from his IT job, my partner finally had the motivation to “learn Linux.” I was extremely happy of course, and figured Linux Mint would be a great starting point for him.

It hasn’t turned out the way I thought it would. After some initial frustrations, he became familiar with the general environment (he has worked in IT for 12 years, he knows how to figure things out). However, when it came to anything command line oriented, or needing my help (as 99% of my solutions are probably through command line/text editing methods) he always seemed to have trouble. He was learning the commands and syntax and problem solving skills, but it didn’t seem to be sinking in as quickly or as deeply as I hoped.

I tried to think how I had gotten to that point where I do most things on the command line, the first thing I thought of was reading/referencing a sparse guide on common utilities and commands. I found and sent him a [better] guide. This didn’t seem to help much.

Finally, this weekend I realized why I was using that guide when I started. My first [real] Linux distro was Slackware, and I had to manually setup my graphical environment. I had to learn by doing, and there was no easy way around it. I realized that while Linux Mint got him going, it made the learning curve gradual, but also made it long.

So, I finally sent him a message from work. “Forget Linux Mint. Try Slackware, Debian, Arch or FreeBSD (I can help out with the last two, been too long for slack or debian).”

Because he isn’t as excited about the BSDs as I am, but wanted my help, he went with Arch. That’s when I remembered the move to pacman 4, and how he’d be setting up package signing manually before he could install anything… hooray for immersion.

Tail-recursive Quicksort?

I’ve been using scheme and racket quite a bit lately, and because I have been playing with functional languages, I have been doing little exercises in solving problems in a more functional approach, which also includes some nice recursion. More specifically, I’ve been trying to think in a more “tail-recursion” approach to take advantage of the scheme systems that are tail-call optimized.

I found this little article, Quicksort: Like You’re 5, which gave a quick implementation- independent demostration of the quicksort algorithm, and being reintroduced to it’s definition, I recongnized it as perfect for recursion! And of course, a good problem for tail-recursion. However, I couldn’t think of how to approach it in a tail recursive manner, so I started by just quickly coding up a quick non-tail recursive version:

(define (quicksort list)
  (if (or (empty? list) (empty? (rest list))) list
      (let ([pivot (first list)]
	    [list (rest list)])
	(append (quicksort (filter ((curry >) pivot) list))
		`(,pivot)
		(quicksort (filter ((curry <=) pivot) list))))))

I got stumped, I couldn’t think of how to accumulate the results for a tail-call. The block I was stuck on was, “Can you tail-call something that branches?” I couldn’t think of a way, and unsure if it was me being naive or it was just not possible. Quick searches on rosettacode and duckduckgo turned up similar approaches to what I did above.

After a good nights sleep, I finally conceded. So you can’t tail-call two separate branches, but you can compute one-branch and tail-call the other, right? After a little bit of fumbling, I came up with this:

(define (quicksort-tail thelist)
  (let quick-acc ([tosort thelist] [acc '()])
    (if (or (empty? tosort) (empty? (rest tosort))) (append tosort acc)
	(let* ([pivot (first tosort)]
	       [tosort (rest tosort)]
	       [acc (append `(,pivot) (quicksort-tail (filter ((curry <=) pivot) tosort)) acc)])
	  (quick-acc (filter ((curry >) pivot) tosort) acc)))))

I haven’t done anything to determine if it’s more time/space efficient, but it works :]

Update: 10-16-2012 I feel pretty dumb about this post. I have been skimming through the newest [unofficial] version of SICP (as I’ve been contemplating making a toy scheme implementation), and while skimming through the section on recursion, I realized why tail-recursion is so important–it’s how you implement iteration. It was a wonderful moment when lots of dangling ends came together to form a strong knot… and then turned around and called me dumb. The final solution is the obvious one as that’s how we iterate through a tree. I essentially arrived at nested iterations in a very convoluted way.

Novelty, Invention and Innovation

Personally, I think TermKit is awesome. I was skeptical at first, but the idea grew on me more and more. I’ve become very interested in novel power-user interfaces, and it seems I keep finding more posts along the same line–describing hypothetical tools and shells. I rarely read comment threads, and I wish I never read the reddit comment thread for this posting–people sure are vehement about changing the Unix Way. I don’t mean to disregard their viewpoint; the Unix philosophy is amazing and versatile and has stood the test of time. Defending something that works well against modernizing with every popular fad is respectable, and discussion from both sides is necessary. However, when the conversation turns to comments such as “Don’t you dare to change and ‘improve’ my terminal,” the credibility fades dramatically.

Is Unix the pinnacle of computing platforms? To think that we have hit our maximum potential seems pessimistic to me. I like to think there is an even better way out there. A new paradigm and a new philosophy that improves on the Unix Way. This may be my chemist side showing, but I deeply believe that we need to encourage experimentation and exploration. Plan 9 and Inferno did not gain wide acceptance, but they tried some new things that have already been adopted and more I think are worth adopting. I think the adoption of procfs/sysfs and the prevalence of plan9port is evidence of that.

I find it comical that despite TermKit being built and emphasized as a layer built over the userland and not a replacement, people still felt threatened by it; as if it’s presence alone would forcibly tear their shell away from them. I call that unjustified paranoia, and also stifling to invention and innovation.

As for the direction I’d like to see things head? Functional programming languages with good parallelization, structured pipes (I like JSON in this regard, or just plain s-exprs), hypertext terminals, and transparent network access via filesystem namespaces (or single system image approaches, like what DragonFly BSD is hoping to accomplish).

I’m hoping to experiment in my spare time with the easier parts of that list, and I’m sure it will be fun. If I’m lucky, maybe I’ll get a long comment thread going too.

This opinionated, fact-void post brought to you by a chemist, who uses computers to get shit done.

Update 12-14-2011: I should mention I have been meaning to learn to use acme as inspiration for some of the above interface ideas, and realized that what I wanted has already been done (sort of). Reading the introduction to Rob Pike’s “Acme: A User Interface for Programmers” states some of the changes I’d like to see. Also, on suckless.org project ideas, the one for a “Yet another less sucking editor” describes the desire to fill a gap between acme and vim.

A Small Rant

I had fun this morning trying to submit some more calculations only to have them all fail, with the log file having one of Gaussians “succinct” error messages that something went wrong in FileIO.

I’ve seen this error before, usually when I’m an idiot and fill up the hard drive with a CIS calculation, or using up all the systems file descriptors (should probably have the advisor increase this…), etc. So, these were the problems I was looking for, and tearing my hair out that everything seemed fine: permissions worked out, there was space, there were enough descriptors.

Finally, I realized all the calculations were restarts/guess=read routes (reads in a checkpoint file) and had forgot to copy the checkpoints to the new filename (as I like to keep the old failed/partial checkpoint in case something goes wrong), which means the FileIO error was because it couldn’t find the checkpoints to read.

For those who don’t use Gaussian: while it is a very very fine program, there are some things that just make you go “WTF?” For example, whenever g09 exits unsuccesfully, it segfaults. Granted, it sets the error code to 1 and to most people it’s no different than a messages that says “Something went wrong! Check the logfile,” but to me this is fundamentally wrong. Segfaults are when a program tries to access memory is can’t/shouldn’t. Think buffer overflows and the such. To me, segfaulting when a program error occurs and the program tries to exit reminds me of a story EHS told us:

A student was heating diethyl ether in a beaker out on a bench top, and with it’s low flash point, it inevitably caught fire from the internal circuitry in the heating plate. Luckily, no one was hurt. However, the student’s solution to this? Do the same thing, but keep a watch glass handy to cover it when it catches fire. So, he sat there covering this thing up whenever it caught fire.

Computational Chemistry Helpers

For the past couple of months, I have been in the process of becoming our group’s computational guy. It has been quite fun (computers and chemistry!), but the work flow has been…interesting.

For example, our group does a lot of radical work, which means spin-density calculations are a common task for me. This requires the cubegen utility when using Gaussian, which takes a number of non-intuitive arguments that don’t change between runs. For a while, I was grep’ing it from my shell history, and editing the file it was to work on. But, I found this annoying, which spawned the following script on a slow day. And because it was a slow day, I went all out.

#!/bin/sh
# just a shortcut to avoid copying and pasting this stupid command over and over and over again

filename=$1

if [ ${filename#*\.} != "fchk" ] ; then
    echo "File not a formatted checkpoint file" 1>&2
    if [ ${filename#*\.} = "chk" ] ; then
	echo "File is a binary checkpoint file. Converting"  1>&2
	formchk ${filename} "${filename%\.chk}.fchk"
	filename="${filename%\.chk}.fchk"
    fi
fi

if [ ${filename#*\.} = "fchk" ] ; then
    cubegen 0 Spin "${filename}" "${filename%\.fchk}-spin.cube" 0 h
fi

At this point, I was also throttling our “super computer” eating up all the file descriptors and causing some other group members calculations to fail… So! instead of just trying to hold myself back and remember which input files I was thinking of running, I threw together this quick script to run a bunch of jobs one by one (originally, this was just a close clone to the one the Gaussian manual lists).

#!/bin/sh

logfile="gaussrun-`date +%m-%d-%y`.log"

echo -e "\nStarting run on `date`:" | tee -a $logfile 1>&2
echo " Running Jobs:" | tee -a $logfile 1>&2
for file in $@ ; do
    if [ -e $file -a "${file#*\.}" = "com" ] ; then
	echo "  $file" | tee -a $logfile 1>&2
    else
	echo "   Error: $file does not exist or is not a Gaussian input file" | tee -a $logfile 1>&2
	exit 1
    fi
done
echo -e "\n" | tee -a $logfile 1>&2
for file in $@ ; do
   echo -e "    -------\n    Starting file $file at `date`" | tee -a $logfile 1>&2
   g09  "${file%\.com}.log"
   echo -e "    $file Done with status $?" | tee -a $logfile 1>&2
done
echo -e "All Done.\n\n" | tee -a $logfile 1>&2

In all honesty though, I am not happy with this one. It’s too static for my tastes. If I want to queue up more jobs, I can’t. I was playing with named pipes and also at/batch, but there wasn’t an easy/obvious way for me to easily add jobs and also be able to look/be told/edit what was in the queue. The qsub command would do just what I wanted it to do, but that requires TORQUE or some other package that isn’t in the repos, and would require asking my advisor to install this package manually. (On a side note, this is the first computer I have used extensively that I do not have root permissions on… I feel so limited T_T )

Lastly, this is the script I am happy with. The problem was trying to setup ONIOM calculations (think of it like an onion, you can use different levels of theory on different shells of the system). For each atom in the system, you need to specify what level of theory to use (for a simple 2 level, you need H for High and L for low), and also you need to specify link atoms (what atoms to replace on the boundry of a shell when doing the higher calculations). None of the programs I use to construct the XYZ input coordinates had any extensions to help me generate these files, and I didn’t look forward to painstakingly editing these 300+ atom files by hand. Luckily, I did find out that using Avogadro, if you copy a selection of atoms and paste into a text editor, it pastes an XYZ formatted list of those atoms you selected. At this point it was just some very clever (and painstaking) construction of proper regexp and sed’ing. I then made a nice script to streamline and error-resist the process (as I may have to show other members how to do these calculations…)

#!/bin/sh
# Formats a gaussian input file for ONIOM calculations
# Requires three files
#   1) The raw gaussin com file (cartesian only for now...)
#   2) An xyz file of all the high level/QM atoms
#   3) An xyz of all link atoms/LA (for the boundry between high and low level, for now assumes H replacement)

#Usage
if [ ${#} -eq 0 ] ; then
    echo 'Usage: oniom.sh comfile [[QM File] [LA file]]'
    echo '    comfile is the raw gaussian input file'
    echo '    QM file is the xyz file of all high level atoms (default is ${cbasename}-QM.xyz)'
    echo '    LA file is the xyz file of all link atoms (default is ${basename}-LA.xyz)'
    exit 0
fi

comfile=$1

if [ ! -e $comfile ] ; then
    echo "File does not exist" 1>&2
    exit 1
fi

if [ ${comfile#*\.} != "com" ] ; then
    echo "File is not a gaussian input file" 1>&2
    exit 1
fi

#directory to use for temp files
TMP="/tmp"

basename=${comfile%\.*}

if [ -e "${basename}-QM.xyz" ] ; then
    qmfile="${basename}-QM.xyz"
elif [ ${#} -ge 2 -a -e "${2}" ] ; then
    qmfile=${2}
else
    echo "No QM file found/specified" 1>&2
    exit 1
fi

if [ -e "${basename}-LA.xyz" ] ; then
    lafile="${basename}-LA.xyz"
elif [ ${#} -ge 3 -a -e "${3}" ] ; then
    lafile=${3}
else
    echo "No LA file found/specified" 1>&2
    exit 1
fi

#copy .com file to /tmp and work on that, copy back here when done
tmpfile="${TMP}/${comfile}"
cp $comfile $tmpfile

#Append all lines matching a atom coordinate with an L (low level)
sed -ri 's/[A-Z][a-z]?( +\-?[0-9]+\.[0-9]+){3}/& L/' $tmpfile

#For all lines in the QM file (matching a molecules coordinate), replace the L with an H
IFS='
'
for line in `grep -E '[A-Z][a-z]?( +\-?[0-9]+\.[0-9]+){3}' "${qmfile}"` ; do
    sed -ri 's/('${line}') L/\1 H/' $tmpfile
done
#For all lines in the LA file (matching a molecules coordinate), append an H
for line in `grep -E '[A-Z][a-z]?( +\-?[0-9]+\.[0-9]+){3}' "${lafile}"` ; do
    sed -ri 's/'${line}' L/& H/' $tmpfile
done

#by this point, should be sucessful, move the tmpfile back
mv $tmpfile $comfile

I am not a fan of shell-scripting and had to [re-]look most of this up, so any suggestions would be welcomed.

Midori, I’m Back!

I have always been a fan of Midori, and I have been using it since before it became part of the XFCE project. It was always very quirky, but I stuck by it. Around the late 0.2.x versions the quirkiness was getting to me, and to scratch an itch I started playing around with different browsers, and eventually settled on chromium as my default browser. ( I had tried uzbl, surf, and all those amazing ‘suckless’ style projects, but they just didn’t work for me, personal preference)

It was faster than Midori, more stable, and, as annoying as this will sound, also worked with Google Docs (I was using it a lot to collaborate with group members on papers and such). There were also some very cool features that I grew to really enjoy and use a lot, such as the ‘Closed Tab History’.  However, chromium also had quirks with it, and what made me furious was it’s disrespect of my system settings (such as my .fonts.conf), there has also been a very frustrating error message appearing lately,

Bad or missing pref 'state' for extension 'hpibmhghjndideebpackbdlpncgkcppp'

I can’t remember what searching for it turned up (I’m sure I did), but this honestly scared me. An ‘extension’ with an obfuscated name was throwing an error. I was able to track this string down to a chromium configuration file and upon inspection realized the file was a load of unreadable XML gibberish.  GIBBERISH! I settled on a clean sweep: wiped my whole chromium directory, any and all related files and directories, did a reboot, reinspected, then started chromium up and began to reconfigure. Upon restarting chromium again, the error reappeared. The obfuscated string was back, but this time I was able to deceiver what it was: my theme.

My Theme! This was infuriating, why did theme information need an obfuscated name, and why did it need all that XML garbage around it! Looking through the rest of the configuration file yielded a lot more crap that I just didn’t understand, and seemed needlessly complicated. I do not know why I did not switch off chromium then and there.

All this came back up when I started to try and version control my home directory (a post to follow soon ;]), and the files upon files of garbage that chromium put in it’s configuration directory were showing up. I didn’t want to have this polluting `hg status`, and I certainly did not want it version controlled. I initially settled for just ignoring it, but I realized that it shouldn’t be this complicated. This browser was a loud forceful and obnoxious party guest that thought it was better than my system and could do as it pleased. I had enough.

I started midori back up to see how the new version was doing (I always have it on my system :]) and realized it had gotten a lot better. I also realized it could now do (or could do and I didn’t realize it) most of the things I found nice about chromium. I found the tab trash, the speed dial has gotten better (with a shortcut to add the current page to it), I figured out how to actually correct misspelled words, and after actually opening up the extensions panel and the FAQ, found I could edit keyboard shortcuts; it has a really cool tab browsing shortcut (ordered by last use!). In the time I was gone, not only did Midori get better, but I also have become more aware of how to use it better. I’m still tweaking it (giving it some emacs style keyboard bindings ;]) but I’m in love with it all over again.

As a last note. A quick comparison (very opinion based, your mileage may vary)

find .config/(midori|chromium) -name "*" | wc -l

Gives 17 files for midori and 62 for chromium (clearing all data brings this down to 49)

Midori has the one [short!] configuration file in readable/editable INI style (simple key=value pairs), with ‘extensions’ having simple definitions with descriptive names. The rest of the files are also in JSON/XBEL format (aside from history/bookmarks, which are in database files for performance reasons).

Follow

Get every new post delivered to your Inbox.