tag:blogger.com,1999:blog-72050415129590927662024-03-08T15:23:05.779-08:00$tail -f findings.outA rollicking adventure through systems administration and programming. Attempts to be useful, skinned with subtle humor.Anonymoushttp://www.blogger.com/profile/06939892570042275807noreply@blogger.comBlogger61125tag:blogger.com,1999:blog-7205041512959092766.post-14356441416839539072008-10-02T11:39:00.000-07:002008-10-02T11:48:52.736-07:00Lost in a sea of terminalsUsually I enjoy my screen being covered with a variety of terminals across multiple servers. But on occasion, I type utterly the wrong thing, in utterly the wrong place, and calamity ensues.<br /><br />So to provide a slight buffer against this, I made a change in my bash prompt. It clues me in if I am on a remote server, a non-personal machine if you will, on which I need to exercise more caution before beating the enter key:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_75nXVfeyezs/SOUW0HIcoqI/AAAAAAAAADE/AauJbo6m89s/s1600-h/Screenshot-shuckins%40web.zenoss.com:+%7E.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_75nXVfeyezs/SOUW0HIcoqI/AAAAAAAAADE/AauJbo6m89s/s400/Screenshot-shuckins%40web.zenoss.com:+%7E.png" alt="" id="BLOGGER_PHOTO_ID_5252629624921039522" border="0" /></a>Just something noticeable, but not overly intrusive. Won't stop idiocy, of course, but it can't hurt.<br /><br />To make it work:<br /><pre><br /># Prompt with easier to read coloring. Define and check for safe boxes:<br />declare -a LOCALBOXES[0]="MyBox1" LOCALBOXES[1]="MyBox2"<br />CURRENTBOX=`hostname`<br />for box in $LOCALBOXES<br />do<br /> if [[ $CURRENTBOX = $box ]] ; then<br /> PS1="\[\033[0;31m\][\T]\[\033[0;36m\]\u@\[\033[1;33m\]\H \[\033[1;34m\]\w: \[\033[0m\]"<br /> else<br /> PS1="\[\033[1;36m\]**REMOTE**\[\033[0;31m\][\T]\[\033[0;36m\]\u@\[\033[1;33m\]\H \[\033[1;34m\]\w: \[\033[0m\]"<br /> fi<br />done<br /></pre>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-7205041512959092766.post-19430503620200247572008-09-22T10:57:00.000-07:002008-09-23T06:13:47.041-07:00ack: grep but better!I came across <a href="http://petdance.com/ack/">ack</a> today, and now grep is sleeping outside. It's very much like grep, except it assumes all the little things that you always wanted grep to remember, but that it never did. It actually left the light on for you, and put the toilet seat down.<br /><br />Anyway, there were some rough bits with installation. On Ubuntu, it is installed by <code>sudo apt-get install ack-grep</code>. If you think, hey, I will take the obvious path and install "ack"! You will be thinking with wrongitude. For <code>ack</code> is, in fact, a Kanji code converter, which I discovered after not a little anger. On RHEL, CentOS, and the like, you have to install with <code>cpan -i App:Ack</code>.<br /><br />Once installed, just try some <code>ack-grep STRING</code>.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_75nXVfeyezs/SNferk8NlPI/AAAAAAAAAC0/gIvv3tdNAjE/s1600-h/Screenshot-shuckins%40ZenSam:+%7E.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_75nXVfeyezs/SNferk8NlPI/AAAAAAAAAC0/gIvv3tdNAjE/s400/Screenshot-shuckins%40ZenSam:+%7E.png" alt="" id="BLOGGER_PHOTO_ID_5248908730955568370" border="0" /></a>Want to ignore .svn dirs? It already did. Want to recursively search? It already did. And it brought over a bag of chips. Read the <a href="http://petdance.com/ack/">Top 10</a> for more goodies.<br /><br />Oh, and don't forget to add <code>ack-grep --thpppt</code> to exit your shell scripts:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_75nXVfeyezs/SNjrbqRgNdI/AAAAAAAAAC8/oJNjM8SMpSk/s1600-h/Screenshot-shuckins%40ZenSam:+%7E.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_75nXVfeyezs/SNjrbqRgNdI/AAAAAAAAAC8/oJNjM8SMpSk/s400/Screenshot-shuckins%40ZenSam:+%7E.png" alt="" id="BLOGGER_PHOTO_ID_5249204226137011666" border="0" /></a>Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-7205041512959092766.post-34668284958213273662008-08-11T21:15:00.000-07:002008-08-11T21:26:01.829-07:00Wordpress contact forms and mailing made less complicatedAfter setting up some Wordpress blogs on my own server, I ran into the problem of wanting a basic contact form that would email myself and users. I in no way wanted to bother setting up my own mail server. I also would prefer not buying SMTP mail service. After a wretched chain of annoying plugins, I came across a salutary trio that met my needs: <a href="http://www.cimatti.it/blog/cimy-wordpress-plugins/cimy-swift-smtp/">Cimy Swift SMTP</a>, <a href="http://ideasilo.wordpress.com/2007/04/30/contact-form-7/">Contact Form 7</a>, and a Gmail surprise.<br /><br />Cimy Swift SMTP allows you to setup SMTP settings, which is perfect if you want to use an external service and not use PHP mail() function. Apparently, Google will let you send mail to any address from any domain using SMTP. Handy! So you just install Cimy, go to its Settings page, put in "smtp.gmail.com" as SMTP server, port 465 (it tells you this is for Gmail), your Gmail user and pass, and that you want TLS (it also notes this is for Gmail. Save, put in a test address, and it should just work. At least it did for me, where others failed.<br /><br />Now you are all dressed up with SMTP, but where to go? I tried a number of contact form plugins that looked great, had lots of features, etc. And none of them bothered using the SMTP settings I put in. Contact Form 7 did, however. It's simple, and takes a little customization to make it look decent. But still, it is a basic contact form that works, and that is all I needed.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-5495482256825823912008-07-16T08:58:00.000-07:002008-07-16T09:05:49.378-07:00Needs more cow...say!I stumbled across a wonderful program today: <a href="http://www.nog.net/%7Etony/warez/cowsay.shtml">cowsay</a>! It is just as cool as you would imagine: <pre>cowsay "Text"</pre>gives you an ASCII-art cow saying your Text.<br /><br />I think I will use it as the welcome banner on all my servers:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_75nXVfeyezs/SH4cRi1CQXI/AAAAAAAAABs/sYJY92CMg2I/s1600-h/cowsay.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_75nXVfeyezs/SH4cRi1CQXI/AAAAAAAAABs/sYJY92CMg2I/s400/cowsay.png" alt="" id="BLOGGER_PHOTO_ID_5223643705528959346" border="0" /></a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-21246687572631738612008-07-10T07:57:00.000-07:002008-07-10T08:42:16.451-07:00Handy Network Utilities: nast, fpingI discovered a wonderful utility last night: <a href="http://www.penguin-soft.com/penguin/man/8/nast.html">nast</a>. I wanted to scan my local network, just to see what devices were on it, what their addresses were, etc. I could ping my entire subnet, but what if I had a machine that rejected ICMP packets? (Not that I do very often, but it can happen in larger environments). I thought using a protocol like ARP would be much more robust, since it is pretty much guaranteed to be available. Then I discovered nast.<br /><br />nast can do a lot of neat things. The first I found was mapping a subnet of course, which you can do by running <pre>sudo nast -i eth1 -m</pre>adjusting the interface to fit. It will return something like: <pre>Nast V. 0.2.0<br /><br />Mapping the Lan for 255.255.255.0 subnet ... please wait<br /><br />MAC address Ip address (hostname)<br />===========================================================<br />00:19:D2:92:20:CE 192.168.1.1 (MyGateway)<br />00:1B:C0:B7:86:CB 192.168.1.2 (MyBox) (*)<br />00:14:38:E5:76:10 192.168.1.5 (SomeOtherBox)<br /></pre> nast can also try to find out if there are any nodes on your subnet acting in promiscuous mode, which I think is pretty hot. Check out the main <a href="http://www.penguin-soft.com/penguin/man/8/nast.html">nast</a> page for the full feature set.<br /><br />In my searching, I also came across <a href="http://fping.sourceforge.net/">fping</a>. Its main improvements over regular old ping are:<br /><ul><li>More than one host can be passed (as well as a file containing hosts)</li><li>Its output is very simple and easy to parse, making it ideal for scripting</li><li>It tries each host and moves on if there is no response, making the whole process faster</li></ul>Instead of <pre>ping -c 1 myhost1 ; ping -c 1 myhost2</pre> you can just run <pre>fping myhost1 myhost2</pre>which just returns <pre>myhost1 is alive<br />myhost2 is alive<br /></pre>Both nast and fping are available in the Ubuntu repos.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-81932176391664382092008-07-09T18:52:00.000-07:002008-07-09T18:58:35.820-07:00Crashing Application GreeterI was playing around with themes and the like in Hardy Heron recently, and I ended up selecting a new login screen. Apparently, something was wrong with the one I installed, however, since the next time I went to login, I was presented with a black screen and the message "The greeter application appears to be crashing. Attempting to use a different one." Hitting Ok on this merely cycled through X starting up and led to the same message.<br /><br />To fix this, I went into another tty with Alt + F2, logged in, and ran "sudo vim /etc/gdm/gdm.conf". I commented out the line "Greeter=/usr/lib/gdm/gdmgreeter" and added "Greeter=/usr/lib/gdm/gdmlogin". After restarting, a simple Gnome login screen appeared fine, which allowed me to get in and change the login screen to a know safe default.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-7205041512959092766.post-55746562626908737312008-07-08T21:29:00.000-07:002008-07-08T21:36:14.898-07:00Additional Tips for GNOME-DoAfter having played with GNOME-Do for a few days, experiencing some pain and finding more fun things, I have some suggestions that may make your adoption of it smoother.<br /><ul><li>Get to 0.5. 0.4 will likely be in your repo, so beware! It is a paltry substitute. If you have installed that, remove it and delete the plugins dir. Then add the repos to your "/etc/apt/sources.list" as <a href="https://wiki.ubuntu.com/GnomeDo/Installation">described here</a>, then run "sudo apt-get install gnome-do". Also, make sure you kill GNOME-Do if it is running, BEFORE you remove the old version and try to install.<br /></li><li>0.5 has a lot of great features, mainly the built-in Preferences window, which lets you just check plugins you want. There is also a new Open With action, which comes in very handy. Get to 0.5.</li><li>Very neat plugins: Skype (lets you chat or call with Skype contacts, like the Pidgin plugin), Upload to Flickr, Locate Files, Rhythmbox.<br /></li><li>Install "xclip" (is in repos). This will let you select any text, invoke GNOME-Do, and act on that text.</li></ul>Once I got to 0.5 and got those plugins running, GNOME-Do started becoming even handier!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-86913838428331359642008-07-03T13:26:00.000-07:002008-07-07T05:57:54.486-07:00Killer App: GNOME-Do!I started to doubt my beloved Ubuntu after a <a href="http://www.catapult-creative.com/">co-worker</a> showed me the various virtues of Quicksilver on the Mac. But, I have... Beagle? Yuck. Lunchbox was cute, but never seemed to work right. But today, I take that doubt back, great Linux gods. Behold: <a href="http://do.davebsd.com/">GNOME Do!</a><br /><br />If you know what <a href="http://www.blacktree.com/projects/quicksilver.html">Quicksilver</a> is, then you are basically there. If you don't, just imagine a pretty app launched by a simple key combo that lets you do anything from open files, to play songs, to email people with just a few easy keystrokes.<br /><br />David Siegel's beautiful site has lots of documentation, plugins, and more. Just be on Gutsy or Heron, add a repo to your sources, install. In case you don't know what "super-space" is, as I didn't, super is the meta key, so the one with a Windows Logo on it on most keyboards.<br /><br />Some additional plugins I installed and found handy:<br /><ul><li>Del.icio.us - Search your bookmarks and public ones<br /></li><li>Rhythmbox - Play songs in your library, control volume, and more<br /></li><li>Pidgin - IM people in your Pidgin lists<br /></li></ul>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-13592558216724748942008-07-02T21:51:00.000-07:002008-07-03T04:45:47.680-07:00Handy script: LAMP stack version printerOften when troubleshooting or setting up servers, I need to know the installed versions of applications commonly grouped into the "LAMP" stack. I dislike having to remember the slight differences between them when trying to coerce each to divulge their version. So I created a script that does that, and even prints it all in easy-to-read colors!<br /><br />The code:<br /><pre>#!/bin/bash<br />###################################<br />#<br /># Written by Samuel Huckins<br />#<br /># July 2007<br />#<br /># Prints out version info for<br /># things in the LAMP stack.<br />#<br />###################################<br />#<br />echo -e "\e[1;34mThis machine's LAMP stack:\e[0m"<br />echo ""<br /># Linux:<br />LINUX=`cat /etc/issue`<br />echo -e -n " * \e[31mL\e[1;33minux: \e[0m"<br />echo "$LINUX"<br /># Apache:<br />echo -e -n " * \e[31mA\e[1;33mpache: \e[0m"<br />if [ -e /usr/sbin/httpd ]<br />then<br />echo "`/usr/sbin/httpd -v| head -n 1 | awk '{print $3}'`"<br />elif [ -e /usr/sbin/apache2 ]<br />then<br />echo "`/usr/sbin/apache2 -v| head -n 1 | awk '{print $3}'`"<br />else<br />echo -e "\e[37mNot present\e[0m"<br />fi<br /># MySQL:<br />echo -e -n " * \e[31mM\e[1;33mySQL: \e[0m"<br />if [ -e /usr/bin/mysql ]<br />then<br />echo "`/usr/bin/mysql --version | awk '/Ver/ {print $2, $3, $4, $5}' | sed 's/,//'`"<br />else<br />echo -e "\e[37mNot present\e[0m"<br />fi<br /># PHP:<br />echo -e -n " * \e[31mP\e[1;33mHP: \e[0m"<br />if [ -e /usr/bin/php ]<br />then<br />echo "`php -v`"<br />else<br />echo -e "\e[37mNot present\e[0m"<br />fi<br /># Perl:<br />echo -e -n " * \e[31mP\e[1;33merl: \e[0m"<br />if [ -e /usr/bin/perl ]<br />then<br />echo "`perl -v | awk '/This is perl/ {print $4}' | sed 's/v//'`"<br />else<br />echo -e "\e[37mNot present\e[0m"<br />fi<br /># Python:<br />echo -e -n " * \e[31mP\e[1;33mython: \e[0m"<br />if [ -e /usr/bin/python ]<br />then<br />echo "`/usr/bin/env python -V 2>&1 | awk '/Python/ {print $2}'`"<br />else<br />echo -e "\e[37mNot present\e[0m"<br />fi<br /># done<br />echo ""<br /></pre>The result:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_75nXVfeyezs/SGy7mSglE5I/AAAAAAAAABk/guVFr5YGdAA/s1600-h/thing7.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_75nXVfeyezs/SGy7mSglE5I/AAAAAAAAABk/guVFr5YGdAA/s400/thing7.png" alt="" id="BLOGGER_PHOTO_ID_5218752334693471122" border="0" /></a>Call it "lamp-version-printer.sh", and add something like "alias lamp="~/my/code/lamp-version-printer.sh". Couldn't be easier.<br /><br />Minor caveat: While the script does check each program for existence, I only check the most common place. It could be better expanded to cover less used locations for applications, conventions on more OSes, etc.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-7205041512959092766.post-33810842337462548242007-10-31T11:08:00.000-07:002007-10-31T11:20:49.397-07:00Reference script for CLI color codesI have been experimenting with adding more color to my bash prompts of late. I find it easier to read when the fields are in distinct colors. The problem I always have is remembering what those wonderfully obscure ANSI escape sequences represent. I always have to look at a table to remind myself that "light red" maps to "1;31".<br /><br />In an interesting guide to configuring your bash prompt that I have been going through, there was a script listed that makes this much easier:<br /><pre>#!/bin/bash<br />#<br /># This file echoes a bunch of color codes to the<br /># terminal to demonstrate what's available. Each<br /># line is the color code of one forground color,<br /># out of 17 (default + 16 escapes), followed by a<br /># test use of that color on all nine background<br /># colors (default + 8 escapes).<br />#<br /><br />T='gYw' # The test text<br /><br />echo -e "\n 40m 41m 42m 43m\<br />44m 45m 46m 47m";<br /><br />for FGs in ' m' ' 1m' ' 30m' '1;30m' ' 31m' '1;31m' ' 32m' \<br /> '1;32m' ' 33m' '1;33m' ' 34m' '1;34m' ' 35m' '1;35m' \<br /> ' 36m' '1;36m' ' 37m' '1;37m';<br />do FG=${FGs// /}<br />echo -en " $FGs \033[$FG $T "<br />for BG in 40m 41m 42m 43m 44m 45m 46m 47m;<br />do echo -en "$EINS \033[$FG\033[$BG $T \033[0m";<br />done<br />echo;<br />done<br />echo<br /></pre>This is from the <a href="http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html">Bash Prompt HOWTO</a>, from a script by Daniel Crisman. It produces the following when run:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_75nXVfeyezs/RyjG4Rs3ciI/AAAAAAAAABM/BFEyJmYoP9Q/s1600-h/color-script-output.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_75nXVfeyezs/RyjG4Rs3ciI/AAAAAAAAABM/BFEyJmYoP9Q/s320/color-script-output.png" alt="" id="BLOGGER_PHOTO_ID_5127566845887869474" border="0" /></a><br />Just add an alias like <code>alias colors="~/dir/of/handy/scripts/print_shell_colors.sh"</code>, and you can be reminded whenever you like.<br /><br />I am still experimenting with my prompt colors, but differentiating the fields I find useful has made things a lot easier:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_75nXVfeyezs/RyjHbRs3cjI/AAAAAAAAABU/wCJwsDvhu1Y/s1600-h/color-prompt.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_75nXVfeyezs/RyjHbRs3cjI/AAAAAAAAABU/wCJwsDvhu1Y/s320/color-prompt.png" alt="" id="BLOGGER_PHOTO_ID_5127567447183290930" border="0" /></a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-90428785393314317792007-10-30T12:20:00.000-07:002007-10-30T12:33:48.964-07:00View compressed log files easilyAny linux distribution around these days will have compression and rotation in place for files in <code>/var/log</code> (or wherever else they happen to go). So if you look in there, you will see one or two log files (current and the last one) for each process logged, as well as 3-7 compressed files for the same process. These then get rotated out.<br /><br />In any case, say you want to look inside one of those compressed log files. You could write out an untar command and then view the file. Then have to delete the temporary file. Messy. There is a better way.<br /><br />The first I found was interesting (from <a href="http://puppylinux.org/wikka/bash">PuppyLinux</a>): Simply run <code>man ./COMPRESSEDFILE</code>. You view the contents of the file with the man file viewer. The annoying thing is that is does funny things with line breaks.<br /><br />A much better way: <code><a href="http://www.mkssoftware.com/docs/man1/zcat.1.asp">zcat</a> COMPRESSEDFILE | less</code>. You view the file in less, and when done, there is no temp file to delete. To make it faster, just add a simple alias: <code>alias viewlog="zcat $1 | less"</code>. This makes viewing those compressed logfiles as painless as viewing the current ones.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-4862265585227861732007-10-23T19:55:00.000-07:002007-10-25T19:52:44.324-07:00Loops in the CLI: Warm and FuzzyIt seems nearly every week, I find something amazingly handy in bash that I had not used before. This time: Loops. I would bet nearly everyone who has written more than a handful of shell scripts over a few lines in length has used one or more of the loops bash has to offer. But, what I realized (not sure why it did not bash me sooner) is that loops are also very effective timesavers as one-off commands in everyday shell usage.<br /><br />I suppose the association came from first using the shell in a very simple way, of just giving commands singly, and only using constructs like loops in scripts I wrote out in files. But recently, I had several identical operations to perform on a series of files with consistent names, and a loop came to mind. The files were all mp4 videos, and I needed to convert them with ffmpeg, and send them through flvtool2. Instead of 2 commands typed out for each file, I ran:<br /><pre class="wiki">for FILE in $(find . -maxdepth 1 -type f -iname \*large.mp4); do ffmpeg -sameq -i $FILE -s 480x270 -ar 44100 -r 10 $FILE.flv; done </pre>You can use loops as like in any shell script, just write the whole loop on one line, separating the conditions, parts in the suite, and the termination with semicolons (these are mostly optional when using line breaks in scripts in files).<br /><ul><li><a href="http://penguinpetes.com/b2evo/index.php?title=how_the_one_liner_for_loop_in_bash_goes&more=1&c=1&tb=1&pb=1.">Post that inspired me</a>, with lots of practical tips for loop usage.</li><li>More <a href="http://tldp.org/LDP/abs/html/loops1.html">advanced loop documentation</a> from TLDP.<br /></li></ul>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-89715524543992994992007-10-23T07:48:00.000-07:002007-10-23T08:15:30.729-07:00Handy Command: Fuser<a href="http://www.linuxcommand.org/man_pages/fuser1.html">Fuser</a> is a very handy command when you are trying to investigate what is listening on a box. Consider the following case. You, being a diligent systems administrator, have been performing regular nmap scans against your boxes from remote hosts. You discover that something is listening on port 587 on a server.<br /><br />What you immediately need to know is: what program is actually listening on that port? The quickest way to find out is to simply run <code>sudo fuser 587/tcp</code> on the box in question. This queries the kernel for what PID is listening on the specified port and reveals almost what you need:<br /><pre>587/tcp: 8102</pre>The first column is the port you specified, the second is the PID using that port currently. This can be combined with ps to give you the desired output, such as via <code>echo `sudo /sbin/fuser 587/tcp` | cut -d' ' -f 2 | xargs ps</code>:<br /><pre> PID TTY STAT TIME COMMAND<br />8102 ? S 14:13 /usr/libexec/postfix/master</pre>I used echo in this case because I was unable to decipher the delimiter used between the two columns in the default output. The whole thing should be aliased such that you run the alias and pass a port, and the ps output is produced.<br /><br />NOTE: <code>fuser</code> is generally found in <code>/sbin</code> or <code>/usr/sbin</code>, which you may have to add to your path.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-25198936992483471842007-10-20T20:21:00.000-07:002007-10-20T21:24:52.163-07:00Easier Sharing: SSHFSMy last post was on how I used Samba to share files from my central media server to other machines on my local network. Seemed great at first, but having used it for a little while, I was rather disappointed. I had Rhythmbox looking at the mounted drive as my library. It started scanning the files once the directory was mounted. I could play them, but after a few minutes, Rhythmbox would freeze scanning the files. In addition, I could not even list the directory that contained the mounted directory. Something was getting frozen. This kept happening more and more, and was quite frustrating.<br /><br />I then tried of SSHFS for the same purpose, and it has been working <span style="font-style: italic;">much</span> better. If you can SSH to the machine with the files you want to share, then you don't have to make any changes to that computer. Just a few steps on the machine that will be accessing the remote store, and you are ready to go. From the top:<br /><ul><li>Create the dir which to which the remote dir will be mounted (e.g. /home/myuser/Music)</li><li>Make sure you have ssh access on remote machine from the local machine</li><li>On the local machine:<br /></li><ul><li><code>sudo apt-get install sshfs<br /></code></li></ul><ul><li><code>sudo modprobe fuse</code></li></ul><ul><li><code>sudo usermod -G fuse -a youruser</code></li></ul><ul><li><code>sudo chgrp fuse /dev/fuse</code></li><li>Logout of myuser on the local machine, then back in</li><li><code>sshfs 192.168.1.6:/dir/on/remote/server LOCALDIR</code><br /></li></ul></ul><code>sudo modprobe fuse</code> will make sure you have that kernel module loaded. You have to be in the fuse group to perform the mount, sudo or not. I am not exactly sure why you have to change the group of the fuse device, but you definitely have to to get it to work.<br /><br />At this point, you should be able to view all the files in /dir/on/remote/server from LOCALDIR. Performance wise, I had great success. Pointing Rhythmbox to the dir I mounted, it scanned all the files in a timely manner, and I was able to play them as if they were on the local machine without issue.<br /><br />If you wish to unmount the share, run <code>sudo fusermount -u LOCALDIR</code>. One problem that has been suggested for which I do not have a fix yet is how to handle if the remote machine has a problem, reboots, or the network connection is otherwise dropped. I am not sure how this would be handled, since the mount would no longer work. fuse being a kernel module, this may cause freezing. If I find this addressed somewhere, I will post it.<br /><br />Additional information and links:<br /><ul><li><a href="http://ubuntu.wordpress.com/2005/10/28/how-to-mount-a-remote-ssh-filesystem-using-sshfs/">General HowTo</a></li><li><a href="http://debaday.debian.net/2007/04/22/sshfs-easy-and-secure-access-to-a-remote-file-system/">Good reference</a></li><li><a href="https://lists.ubuntu.com/archives/ubuntu-users/2006-June/080743.html">Post on changing /dev/fuse owner</a><br /></li></ul>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-7205041512959092766.post-83508642241630516502007-10-19T20:39:00.000-07:002007-10-19T20:53:27.630-07:00Quick and Handy Samba SetupI just never got around to setting up and using Samba on my home network. I had my files in SVN or would login to the box that had what I needed, or used some other mechanism. But a certain case kept popping up that forced me to get it in place.<br /><br />I have one server that has all of my movies, music, etc on my home network. I wanted to be able to access all my music from other machines. Using gnump3d was, aside from annoying for long term listening, a waste of bandwidth. Instead, I created a share on my media server accessible without password only on my LAN, and mounted this as my music library on my other machines.<br /><br />To set up the first part, I followed <a href="http://www.debuntu.org/guest-file-sharing-with-samba">this handy tutorial</a>. He has all the details, but basically you just installed samba on the machine you want to share from, edit the conf file to create a share with no password access locally, and restart samba.<br /><br />Then, on the machine you want to access the files from, you install smbfs. After that, create a dir you want to mount the shared files from (in my case ~/Music), then run<br /><code>sudo smbmount //myserver/myshare ~/mnt.</code> After that, you should be able to browse files you are sharing from the mountpoint you specified. Easy!<br /><br />More details on setting up Samba, as well as having a shared directory mount on boot, may be found <a href="https://help.ubuntu.com/community/SettingUpSamba">here</a>. One last thing. smbclient allows you to find information on local shares from the machine you are sharing from. For example, <code>smbclient -L SERVERNAME</code> allows you to see all available shares on SERVERNAME.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-7205041512959092766.post-59872807141656930822007-10-16T15:57:00.000-07:002007-10-18T18:22:42.453-07:00More Tasty Tips for DenyHostsAfter living with DenyHosts for some time, I have made some additional configuration changes that are quite helpful.<br /><ol><li><span style="font-weight: bold;">Whitelist known good IPs</span><br />I found after not very long that my home IP address had been added to my webserver's hosts.deny file by DenyHosts. This was a result of having messed up my own login a few times. This could easily be an issue if you are regularly connecting to the box running DenyHosts (from work, home, etc).<br />A simple solution: Add your IP to an allowed-hosts file in your DenyHosts working directory. Once that is in place, you might also need to find and remove the entry for the IP in question from your hosts.deny file (if it has already been added). It would be a wise choice to add known good IPs to allowed-hosts when you first setup DenyHosts. Otherwise, you might find yourself blocked from your server with no way to get access!<br />For more details, see <a href="http://denyhosts.sourceforge.net/faq.html#allowed">the FAQ</a>.<br /></li><li><span style="font-weight: bold;">Blacklist bad users</span><br />It is also a good idea to add users you know are not allowed in a restricted-usernames file in your DenyHosts working directory. This keeps users that should never be allowed to login from trying, even once. There are two handy scripts provided to help in generating this list (located in the scripts dir of your DenyHosts working dir).<br />The first, restricted_from_passwd.py, scans your /etc/passwd file and outputs users who have nologin set (print daemons, etc). You can redirect this to your restricted-usernames file.<br />The second script is only handy after you have been running for some time. restricted_from_invalid.py, when passed your working dir, prints out the users which bad SSH attempts use most often. By default, it prints the top 10. You could also pass it a large number, say 10000, and it would print all the bad users ever attempted since DenyHosts was first started. I take this list, remove the users I have in place and know to be good, and use it as my restricted-usernames list.</li><li><span style="font-weight: bold;">Set the purge threshold and purge rate</span><br />In your denyhosts,cfg file, set PURGE_DENY to something reasonable, 1 - 2 weeks perhaps. Otherwise, your hosts.deny might good huge.<br />Then, set the PURGE_THRESHOLD to 2 -3. This means that while entries older than your PURGE_DENY will be removed from the deny list, if it occurs more than your PURGE_THRESHOLD, they will not be purged. This is more likely to stop the entries most often attempted.<br /></li><li><span style="font-weight: bold;">Rotate log files</span><br />Assuming you have logrotate installed (and why don't you?), the FAQ has <a href="http://denyhosts.sourceforge.net/faq.html#2_25">a great example</a> file for adding a rotate entry for DenyHosts.<br /></li><li><span style="font-weight: bold;">Sync with central DenyHosts database</span><br />One feature which really makes DenyHosts shine is the ability to share known rogue agents among DenyHosts instances. It is off by default, but to turn it on, edit denyhosts.cfg in your working dir. To enable synchronization, simply uncomment SYNC_SERVER. The value it is set to should be correct. By default, once synchronization is one, every hour the daemon will check with the server specified. It will upload hosts that you have denied, and download hosts that at least 3 others have denied. If you wish, you can tweak the timing of this process, just to upload, the threshold for downloading, etc.<br />For more details, see <a href="http://denyhosts.sourceforge.net/faq.html#4_0">the FAQ</a>.</li></ol>After these changes are made, be sure to restart DenyHosts via <code>sudo /usr/share/denyhosts/daemon-control restart</code>.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-71478210953442838852007-10-15T18:47:00.000-07:002007-10-15T19:00:29.739-07:00DenyHosts: Watches your SSH log for youWhile I knew that brute-force attacks on SSH servers are very common, I had not taken the time to look at the connection attempt logs on my home servers until recently (to do that, by the way, on Ubuntu, try <code>sudo tail -n 100 /var/log/auth.log</code>). I was seeing attempts every few seconds for some periods, mostly on non-standard ports!<br /><br />So far as I knew, no one had gotten through, but why risk the worry. Instead I installed <a href="http://denyhosts.sourceforge.net/">DenyHosts</a>. DenyHosts is a Python script that watches your auth.log, and adds IPs that repeatedly try and fail to connect to the <code>/etc/hosts.deny list</code>, effectively denying then future access.<br /><br />It is rather easy to install. There is a <a href="http://packages.ubuntu.com/edgy/net/denyhosts">package</a> in the repos, but I was unable to get this to work on my servers for some reason (it is still in testing). I instead followed <a href="http://www.howtoforge.com/preventing_ssh_dictionary_attacks_with_denyhosts">this handy tutorial</a>. It worked flawlessly, with one exception. I had to run <code>sudo touch /etc/hosts.deny</code> right before starting the service. Otherwise it threw an error that the file did not exist and closed. With the touch, all went fine. That fix was listed in <a href="https://bugs.launchpad.net/ubuntu/+source/denyhosts/+bug/87898">this bug report</a>.<br /><br />A few other notes:<br /><ul><li>If you have not done so, be SURE to change this line in <code>/etc/ssh/sshd_config</code>:</li><ul><li><code>PermitRootLogin no</code></li></ul><li>While editing <code>/usr/share/denyhosts/denyhosts.cfg</code> according to the tutorial, I recommend (following others posting this tip) to also change this line:</li><ul><li><code>BLOCK_SERVICE = ALL</code>. Also, of course, comment the line: <code>BLOCK_SERVICE = sshd</code>. This blocks access on all ports to IPs that get denied. And really, if you want to block a potentially malicious IP from SSH access, why give them access to other services?<br /></li></ul></ul>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-14519775291992491242007-10-13T08:33:00.000-07:002007-10-13T17:53:37.093-07:00Topping top: htopTop is a very handy and common application. But there is always room for improvement, even in common and simple programs. In this case, meet <a href="http://htop.sourceforge.net/index.php?page=main">htop</a>. It performs a similar function to top, viz. showing you what is using your system's CPU, memory, or other resources. However, htop presents this information is a much friendlier graphical way.<br /><br />On Ubuntu, install is a snap. Make sure you have the universe repos enabled, and then run <code>sudo apt-get install htop</code>.<br /><br />And no more obscure commands to remember for configuring layout and appearance. There is a handy list of commands at the bottom of the display. In addition, that display is in a wide range of handy colors (also configurable of course). The whole presentation is easier to read, and a lot easier to customize.<br /><br />As mentioned, there are a lot of options for htop. Once you configure things and exit htop, your changes are saved to a .htoprc in your home directory. To see the basic options I have set, you can check out <a href="http://launchpod.homelinux.com:81/trac/configuration/browser/htop/.htoprc">my .htoprc.</a><br /><br />I like to have top (and now htop) running in the top left of my dual monitor setup. Using fluxbox, this is rather easy. See my .fluxbox <a href="http://launchpod.homelinux.com:81/trac/configuration/browser/fluxbox/homepc/startup">startup</a> and <a href="http://launchpod.homelinux.com:81/trac/configuration/browser/fluxbox/homepc/apps">apps</a> files.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_75nXVfeyezs/RxFodEUXgrI/AAAAAAAAABE/ljTWn-XyZiU/s1600-h/htop.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_75nXVfeyezs/RxFodEUXgrI/AAAAAAAAABE/ljTWn-XyZiU/s320/htop.png" alt="" id="BLOGGER_PHOTO_ID_5120989099881628338" border="0" /></a>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-7205041512959092766.post-21820757418042969922007-10-08T12:02:00.000-07:002007-10-08T12:22:16.189-07:00Run vim without being there...Say you have a text file. You need to alter it in some regular way before sending it on somewhere else. Instead of editing by hand, there is a neat option you can use to edit the file with familiar vim commands (instead of awk's lovely syntax), without having to open vim interactively.<br /><br />The principle is simple: You make a file containing each of the commands you want to run, one per line. They will be the same form as if you typed them in a vim session, starting with ":". Make sure that ":wq" is the last one. Then you run vim with:<br /><pre>vim -s FILEOFCOMMANDS.txt FILETOEDIT.txt</pre>Example case. My file to edit is tester.txt, contents being:<br /><pre>64.114.33.23,www.example.com<br />64.114.33.24,www.example.co.uk<br />64.114.33.25,www.example.co.jp<br />64.114.33.26,www.example.co.fr<br />64.114.33.27,www.example.co.cz</pre>Then I have a <code>commands.txt</code> file containing:<br /><pre>:%s/^/("<br />:%s/,/","<br />:%s/$/"),<br />:wq</pre>Finally I ran it as <code>vim -s commands.txt tester.txt</code>. As a result, <code>cat tester.txt</code>:<br /><pre>("64.114.33.23","www.zenoss.com.co.uk"),<br />("64.114.33.24","www.zenoss.com.co.de"),<br />("64.114.33.25","www.zenoss.com.co.fr"),<br />("64.114.33.26","www.zenoss.com.co.cp"),<br />("64.114.33.27","www.zenoss.com.co.jp"),<br /></pre>You could put something like this in a cron job, making transitions between data manipulation steps quick and easy, without having to mess with the files by hand each time.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-7205041512959092766.post-52070824451338772512007-10-07T12:33:00.000-07:002007-10-08T11:17:08.532-07:00Handy Alias: Grab latest svn logI keep having the occasion to view the log comments for the current revision in my SVN repository. This means:<br /><ul><li>Knowing the number of the current revision,</li><li>Passing this to <code>svn log -r</code></li></ul>Instead of doing that by hand, I made an alias to do it for me:<br /><pre>alias svnlastlog="svn info | grep 'Last Changed Rev' | cut -d ' ' -f 4 | xargs -I mystr svn log -r mystr"</pre>So if you are in a directory that is versioned, you just run that command, and (after being prompted to authenticate to your repo, if applicable), out comes the log entry for the current revision. Perhaps there is a built in command to do this already, but I could not find it via Google and the SVN Book.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-7205041512959092766.post-35089927252377501632007-10-01T20:44:00.000-07:002007-10-01T20:49:38.434-07:00What are all the wxPython Events?On several occasions recently I found did not know what event to specify to trigger something in my wxPython apps. I had a hard time finding anything close to a comprehensive list of all events available, so I was limited to posting questions on the <a href="http://www.wxpython.org/maillist.php">wxPython users mailing list</a>. And, while this is a wonderful and active list, it would be nice to have a guide even closer at hand.<br /><br />Cody Precord on the list provided me with a handy way to get this:<br /><pre>import wx<br /><br />for x in dir(wx):<br /> if x.startswith('EVT_'):<br /> print x</pre>Run that, and out comes a list of all the <code>EVT</code> types. Of course, in some cases you may not know what the event is just from the name, but they are mostly suitable self-explanatory. See for yourself:<br /><br /><pre>EVT_ACTIVATE<br />EVT_ACTIVATE_APP<br />EVT_BUTTON<br />EVT_CALCULATE_LAYOUT<br />EVT_CHAR<br />EVT_CHAR_HOOK<br />EVT_CHECKBOX</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-23180090492496990522007-09-26T20:48:00.000-07:002007-09-26T17:49:17.618-07:00Clean your code: Pylint<a href="http://www.logilab.org/857">pylint</a> is a tool that "analyzes Python source code looking for bugs and signs of poor quality". Now, that can mean optimizing and cleaning your code at a fairly advanced level at which, if you are a beginning programmer like me, you will not get much out of.<br /><br />However, it can help with lots of small checking too, and improve the form of your Python code in a quick and convenient manner. It will show you problems you might not even know were problems! I have not gotten into too many of the features myself, but some quick examples should show you its utility. Getting it is pretty simple. On Ubuntu for example, installing is only a matter of <code>sudo apt-get install pylint</code>. To run it, just do <code>pylint YOURAPP.py</code>.<br /><br />It can take a little while to run, and then it spits out several blocks of results. Some examples:<br /><ul><li><code>C: 68: Line too long (154/80)</code></li><ul><li>One of the lines in the file has way too many characters. It is recommended to keep each line at 79 characters or less. To learn why, check out <a href="http://www.python.org/dev/peps/pep-0008/">PEP 8</a>, under "Code Lay-out", "Maximum Line Length".<br /></li></ul><li><code>C: 5: Operator not preceded by a space<br />__version__="0.1"</code></li><li><code>W: 40:Frame.__init__: Unused variable 'statusbar'</code></li><ul><li>No need for this variable anymore, just taking up space.<br /></li></ul><li><code>C: 93:App.OnInit: Invalid name "OnInit" (should match [a-z_][a-z0-9_]{2,30}$)</code></li></ul>As can be seen from these examples, the alerts are pretty easy to read. pylint also shows you how many lines are duplicated, metrics such as how many lines of code versus docstrings, how many modules, and more. In the end, it gives your code an overall score. If you fix some errors and re-run it, it will show you your current and previous scores.<br /><br />To start using the more advanced features, peruse <a href="http://linux.die.net/man/1/pylint">the man page</a>. Now, go clean your code.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-12988978568225285432007-09-24T19:13:00.000-07:002007-09-24T19:34:27.205-07:00Tips: Toolbar icons in wxPythonI have started playing around with <a href="http://www.wxpython.org/">wxPython</a>, a great toolkit for making clean, cross-platform, flexible GUIs in Python. While there are a lot of great tutorials out there on how to get started making apps with wxPython, having <a href="http://www.manning.com/rappin/">The Book</a> has been a definite boon.<br /><br />While going through the basic exercises and starting to make my own GUIs, I kept running into an issue that got more and more annoying: toolbar icons. I wanted to have a toolbar, with some basic icons, for actions like New, Open, etc. In the book, Rappin and Dunn give an example of using toolbar icons (p49). The pertinent part:<br /><pre>import wx<br />import images<br />[SNIP]<br />toolbar = self.CreateToolbar()<br />toolbar.AddSimpleTool(wx.NewId(), images.getNewBitMap(), "New", "Long help for 'new'")<br />toolbar.Realize()</pre>This in no way works. When I ran it on Ubuntu (7.04), I got:<br /><br /><pre>ImportError: No module named images</pre><br />After some Googling, I found this is a common problem for beginners. Lots of related example code will be similar to the above, but specify something like "stock_new.png" for the image. To get all these to work, you actually need to download some images, and specify those. Seems obvious after the fact, but it seemed quite possible to me starting out there there would be a built-in facility to grab OS-specific icons for basic tasks such as New and Load.<br /><br />A great source of good-looking free icons for desktop applications is the <a href="http://tango.freedesktop.org/Tango_Icon_Gallery">Tango Desktop Project</a>. Sometimes that page is down or takes a very long time to load. If so, you can download the .zip on <a href="http://art.gnome.org/themes/icon/1150">this page</a>. Every icon you will likely want for a toolbar may be found in "actions", once you extract the Tango folder and select an icon size to use. I found it helpful to place the icons I wanted in a "resources" folder in the folder holding my application, and use them with code such as:<br /><pre> toolbar = self.CreateToolBar()<br /> toolbar.AddSimpleTool(wx.NewId(), wx.Image('resources/document-new.png',<br /> wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'New', 'Long help for New')<br /> toolbar.AddSimpleTool(wx.NewId(), wx.Image('resources/document-open.png',<br /> wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Open', 'Long help for Open')<br /> toolbar.AddSimpleTool(wx.NewId(), wx.Image('resources/document-save.png',<br /> wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Save', 'Long help for Save')<br /> toolbar.Realize()</pre>That will result in something like the following (Menubar added for positional context):<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_75nXVfeyezs/RvhzLEUXgqI/AAAAAAAAAA8/NDterSh-UUc/s1600-h/toolbar.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_75nXVfeyezs/RvhzLEUXgqI/AAAAAAAAAA8/NDterSh-UUc/s320/toolbar.png" alt="" id="BLOGGER_PHOTO_ID_5113964010854122146" border="0" /></a>Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-7205041512959092766.post-70531954174315223592007-08-25T20:43:00.001-07:002007-08-25T20:53:34.370-07:00Quad terminal laser!I find, not too infrequently, that I need to perform operations across several directories, or across several servers, at once. To best facilitate this, I usually open 3-5 terminals, and then move them around so that I can see them all at once. Why not automate this, I thought. Instead of hard coding sizes and positions for the terminals and assigning the sequence to a keypress, I thought I would do something more useful and write a Python script to find out this information based on the current display, and launch the terminals appropriately.<br /><br />This has been completed, but the script still has a lot to be desired. You still have to set as a variable whether dual monitors are being used (could not find a way to determine this programatically yet), and it only works with single monitor or TwinView in Linux. You can also set what sort of terminal you want to use (gnome-terminal is default), what side you want them to open on for dual monitor setups (right is default), and what directory they should be in (user's home dir is default). It gets your screen's dimensions, calculates where the terminals should be and how they should be separated, and launches them.<br /><br />I then added this to my <code>.fluxbox/keys</code> file:<br /><pre>Mod1 q :ExecCommand python /home/sam/code_homerepo/code/userextensions/quadterm.py</pre>So now I just press "Alt + q", and four gnome-terminals launch perfectly spaced on my right monitor!<br /><br />The code is quite ugly right now, but as it stands:<br /><pre>#/usr/bin/python<br />#####################################################<br /># Creates 4 terminals evenly quartering a screen<br />#<br /># Linux only right now. Map it to a keystroke for<br /># maximum convenience.<br />#<br /># If you don't want to use gnome-terminal, change the<br /># next variable. Warning: The width and height<br /># specified are in characters and rows for gnome-<br /># terminal; they might have to be in pixels for other<br /># apps.<br />#####################################################<br />terminal = "gnome-terminal"<br />#####################################################<br /># If you are not using TwinView, toggle the following:<br />#####################################################<br />twinview = True<br />#####################################################<br /># Which monitor (if Dual) you want them on:<br />#####################################################<br />side = "right"<br />#####################################################<br /># Dir the terminals will be in:<br />#####################################################<br />workingdir = "~"<br />#####################################################<br />import commands<br /># Get the screen dimensions:<br />dimeninfo = commands.getoutput("xdpyinfo | grep dimensions")<br /># Read out the needed numbers:<br />dimeninfosplit = dimeninfo.split()<br />dimensions = dimeninfosplit[1]<br />prex = dimensions.split("x")<br />x = int(prex[0])<br />prey = dimensions.split("x")<br />y = int(prey[1])<br /># Take some visual buffers into account:<br />widthsansborder = x - 50<br />heightsansborder = y - 50<br /># Calculate dimensions in pixels:<br />termwidthpixels = widthsansborder / 2<br />termheightpixels = heightsansborder / 2<br /># Convert to characters/rows for most apps (like gnome-terminal).<br /># No idea what the conversion rate should be...<br />termwidth = termwidthpixels / 16<br />termheight = termwidthpixels / 60<br /># Constant width/height for all 4.<br />t1width = t2width = t3width = t4width = termwidth<br />t1height = t2height = t3height = t4height = termheight<br /># Find the offset position for appropriate pairs (in pixels):<br />t1posx = t3posx = 50<br />t2posx = t4posx = (50 * 2) + termwidthpixels<br />t1posy = t2posy = 50<br />t3posy = t4posy = 50 + termheightpixels<br /># If TwinView is being used, we need to halve some offsets:<br />if twinview is True:<br /> t2posx = (((50 * 2) + termwidthpixels) / 2)<br /> t4posx = (((50 * 2) + termwidthpixels) / 2)<br /> if side == "right":<br /> t1posx = 50 + (x / 2)<br /> t2posx = x * .75<br /> t3posx = 50 + (x / 2)<br /> t4posx = x * .75<br /># Spawn the 4 terminals, with needed positions and sizes, then exit quietly:<br />commands.getoutput("%s --geometry=%dx%d+%d+%d --working-directory=%s" % \<br /> (terminal, t1width, t1height, t1posx, t1posy, workingdir))<br />commands.getoutput("%s --geometry=%dx%d+%d+%d --working-directory=%s" % \<br /> (terminal, t2width, t2height, t2posx, t2posy, workingdir))<br />commands.getoutput("%s --geometry=%dx%d+%d+%d --working-directory=%s" % \<br /> (terminal, t3width, t3height, t3posx, t3posy, workingdir))<br />commands.getoutput("%s --geometry=%dx%d+%d+%d --working-directory=%s" % \<br /> (terminal, t4width, t4height, t4posx, t4posy, workingdir))<br /># For debugging, print what we have calculated:<br />#print "%s at: %d x %d + %d + %d" % (terminal, t1width, t1height, t1posx, t1posy)<br />#print "%s at: %d x %d + %d + %d" % (terminal, t2width, t2height, t2posx, t2posy)<br />#print "%s at: %d x %d + %d + %d" % (terminal, t3width, t3height, t3posx, t3posy)<br />#print "%s at: %d x %d + %d + %d" % (terminal, t4width, t4height, t4posx, t4posy)<br /></pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-7205041512959092766.post-77674175199255500732007-08-23T11:21:00.001-07:002007-08-23T11:34:14.705-07:00All your base...Master Ian (whom I would link to, if his blog were not continually DOWN), showed me a very simple yet useful command: <a href="http://www.mkssoftware.com/docs/man1/basename.1.asp"><code>basename</code></a>.<br /><br />You give it the path to a file, it gives you the filename and extension. If you also give it the extension, it just gives you the filename. Thus:<br /><pre>sam@ZenSam:~$ basename unique-ip-list.csv<br />unique-ip-list.csv<br />sam@ZenSam:~$ basename unique-ip-list.csv .csv<br />unique-ip-list</pre>This could be quite useful in shell scripting, to grab a list of desired for various purposes. One implementation I thought of right off: If you wanted to throw an error message for the usage of a command in a script, instead of having it display "See /usr/bin/zip for details" or something similar, you could run it through basename, and get a better looking name.Unknownnoreply@blogger.com0