<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>phaq &#187; Scripting</title>
	<atom:link href="http://phaq.phunsites.net/category/faq/programming/scripting/feed/" rel="self" type="application/rss+xml" />
	<link>http://phaq.phunsites.net</link>
	<description>my daily IT madness</description>
	<lastBuildDate>Sun, 05 Feb 2012 21:06:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<item>
		<title>VpnInit AppleScript: Override and Restore Default VPN-Routes on OS X</title>
		<link>http://phaq.phunsites.net/2011/12/29/vpninit-applescript-override-and-restore-default-vpn-routes-on-os-x/</link>
		<comments>http://phaq.phunsites.net/2011/12/29/vpninit-applescript-override-and-restore-default-vpn-routes-on-os-x/#comments</comments>
		<pubDate>Thu, 29 Dec 2011 17:37:04 +0000</pubDate>
		<dc:creator>gdelmatto</dc:creator>
				<category><![CDATA[Networking]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Utilities]]></category>

		<guid isPermaLink="false">http://phaq.phunsites.net/?p=876</guid>
		<description><![CDATA[Years ago I wrote a small script to restore local default route after connecting the RAS VPN on Windows. Now, I made up a similar script to do the same on OS X. The basic idea, now and then, was that I would not want to send all traffic through the VPN. Thus the script [...]]]></description>
			<content:encoded><![CDATA[<p>Years ago I wrote a small script <a href="/2007/06/06/ras_initvbs-override-and-restore-routes-with-windows-ras/">to restore local default route after connecting the RAS VPN on Windows</a>.</p>
<p>Now, I made up a similar script to do the same on OS X.<br />
<span id="more-876"></span><br />
The basic idea, now and then, was that I would not want to send all traffic through the VPN.<br />
Thus the script will assist in restoring your local default route after the VPN connection is established.<br />
Furthermore, it&#8217;ll add some specific routes directed to the VPN.</p>
<p>This way, all your usual traffic (internet, surfing, skype, whatever) is sent through your default gateway, while more specific routes (your business stuff) is sent through the VPN.</p>
<p>Below&#8217;s the code for the initial release. It may lack some details yet, like auto-detecting the tunnel device name, but it does the job already.</p>
<p>Just copy the code into Apple Script Editor and save it to a convenient location. Make sure you save it as &#8220;Application&#8221; and not as &#8220;Script&#8221; (which is the default). You you don&#8217;t, double-clicking the script will open the Script Editor instead of executing the script. Surely, not what you want.</p>
<p>Pay attention to the variables on the top, which need to be edited before you save the Script: _vpn_name, _default_gw, _networks, and _sudo_password (optional).<br />
I hope directions are clear enough from the comments sections.</p>
<pre>
# VpnInit
# ---
# an AppleScript utility to connect your vpn,
# restore local default route and add selected
# routes directed to the VPN only
# thus you'll end up sending only selected
# traffic through the VPN, while the rest
# goes through your local default gateway
# as usual
# ---
# released "as is" under the terms of GPL v2.
# Copyright © 2011 Gianpaolo Del Matto
# 
# r0.1 initial release 2011/12/29
#
# ToDo:
# - hardcoding the "sudo" password is a bad idea, maybe
#	need a better way to get away with it
# - vpn tunnel (utun0) is still hardcoded,
#	should be auto-detected
#

# the name of your vpn connection
#
set _vpn_name to "My VPN"

# your local default gateway
#
set _default_gw to "192.168.1.1"

# your remote networks to pass via VPN, separate multiple with comma
# like so: {"1.2.3.4/30", "5.6.7.8/30"}
#
set _networks to {"192.168.2.1/24"}

# your super-user (root) password
# actually needed to bypass the prompts
# leave empty to get prompted
#
set _sudo_password to ""

# ##################################################################
# DO NOT CHANGE ANYTHING BELOW
# ##################################################################

# kindly borrowed from
# http://www.macosxautomation.com/applescript/uiscripting/index.html
# make sure that support for assistive devices is enabled
#
tell application "System Events"
	if UI elements enabled is false then
		tell application "System Preferences"
			activate
			set current pane to pane id "com.apple.preference.universalaccess"
			display dialog "This script requires access for assistive devices be enabled." &amp; return &amp; return &amp; "To continue, click the OK button and enter an administrative password in the forthcoming security dialog." with icon 1
		end tell
		set UI elements enabled to true
		if UI elements enabled is false then
			display dialog "This script cannot run while access for assistive devices is disabled." &amp; return &amp; "Exiting now." buttons {"OK"} with icon 2
			return "user cancelled"
		end if
	end if
end tell

# now dive into the VPN setup part
#
tell application "System Events"
	set _if_tunnel to "utun0" #	do not change, will be auto-detected, just giving a reasonable default
	tell current location of network preferences
		if exists service _vpn_name then
			# try to connect the VPN service if it's disconnected
			#
			if current configuration of service _vpn_name is not connected then
				connect service _vpn_name
			end if

			# give it some time to settle
			#
			set _retval to false
			repeat until (_retval) is true
				set counter to 0
				repeat while counter is less than 16
					# exit if we get connected
					#
					if current configuration of service _vpn_name is connected then
						set _retval to true
						exit repeat
					end if

					# opt for exit if still not connected after 15 seconds
					#
					if counter is equal to 15 then
						display dialog "VPN '" &amp; _vpn_name &amp; "' is still not connected after 15 seconds. Do you want to keep waiting?" with title "VPN still not connected" buttons {"Yes", "No"}
						if button returned of result is "No" then
							# bail out if user decided not to wait any longer
							#
							set _retval to true
							return
						else
							# otherwise reset the counter so we can trigger again
							#
							set counter to 0
						end if
					end if

					set counter to counter + 1
					delay 1
				end repeat
			end repeat

			# now go to post processing and to the following:
			# - delete default route via vpn
			# - restore original default route
			# - add specific routes to vpn
			#
			if current configuration of service _vpn_name is connected then
				# restore local default route
				#
				do shell script "route delete default" password _sudo_password with administrator privileges
				do shell script "route add default " &amp; _default_gw password _sudo_password with administrator privileges

				# inject custom routes via VPN
				#
				repeat with _network in _networks
					do shell script "route add -interface " &amp; _network &amp; " utun0" password _sudo_password with administrator privileges
				end repeat
			end if
		else
			# bail out if the VPN service does not exist
			#
			display dialog "Given VPN '" &amp; _vpn_name &amp; "' does not exist. Please check the name"
		end if
	end tell
end tell
</pre>
]]></content:encoded>
			<wfw:commentRss>http://phaq.phunsites.net/2011/12/29/vpninit-applescript-override-and-restore-default-vpn-routes-on-os-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automating MakeMKV with AppleScript</title>
		<link>http://phaq.phunsites.net/2011/12/15/automating-makemkv-with-applescript/</link>
		<comments>http://phaq.phunsites.net/2011/12/15/automating-makemkv-with-applescript/#comments</comments>
		<pubDate>Thu, 15 Dec 2011 21:56:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[OS X]]></category>
		<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://phaq.phunsites.net/?p=858</guid>
		<description><![CDATA[It&#8217;s only days since I wrote about a custom script action upon inserting a DVD in OS X, allowing me have either run the DVD Player or MakeMKV to rip the DVDs. Now I was digging around if I could do some automation on the GUI part, which indeed turned out to work &#8230; at [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s only days since I wrote about <a href="/make-os-x-run-custom-actions-upon-dvd-insert">a custom script action upon inserting a DVD</a> in OS X, allowing me have either run the DVD Player or MakeMKV to rip the DVDs.</p>
<p>Now I was digging around if I could do some automation on the GUI part, which indeed turned out to work &#8230; at least to a certain degree.<br />
<span id="more-858"></span><br />
Let&#8217;s face it: Ripping DVDs with MakeMKV is simple and easy, however its scripting abilities s*** <img src='http://phaq.phunsites.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>There is actually some limited CLI support available. If you dive into the application package, you&#8217;ll find the <b>/Applications/MakeMKV.app/Contents/MacOS/makemkvcon</b> program, which can be scripted somehow.</p>
<p>In the first place, I was perfectly able to rip off a complete DVD using the CLI command. But that was not what I had in mind, because I wanted to select only the main movies, and there only a limited set of audio streams and subtitles.<br />
As I seemed to be unable to figure out, how that would be possible (some rare comments on the <a href="http://www.makemkv.com/forum2/" target="_blank">MakeMKV forums</a> mentioned, that it would NOT be possible), I ended up using the GUI.</p>
<p>Well, after I wrote the auto-selector script, I started thinking on how to make this a bit more practical.<br />
I know Apple released support for GUI (graphical user interface) scripting already years ago, but I had never really looked into until today <img src='http://phaq.phunsites.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>After some reading over there at <a href="http://www.macosxautomation.com/applescript/uiscripting/index.html" target="_blank">macosxautomation.com</a> I started on extending my script.<br />
Please consider that you need to enable support for assistive devices, as mentioned on macosxautomation.com &#8212; otherwise the script will simply fail.</p>
<p>With help of <a href="http://pfiddlesoft.com/uibrowser" target="_blank">UI Browser</a>, a utility to explore GUI elements of any application, I was able to identify the relevant items.</p>
<p>So with the latest additions, the script does the following:</p>
<ul>
<li>Runs whenever a DVD is inserted</li>
<li>Automatically run DVD Player if no action is taken &#8211; or -</li>
<li>run MakeMKV if requested to do so</li>
<li>Wait for the DVD TOC (table of contents) to be read initially</li>
<li>As soon as the TOC is read, open the DVD in MakeMKV</li>
<li>Wait until the tracks selected were ripped and try to eject the DVD afterwards</li>
</ul>
<p>And here&#8217;s the code:</p>
<pre>
# dvd-action
# ---
# an AppleScript utility to select DVD Player or MakeMKV
# upon inserting a DVD
# ---
# released "as is" under the terms of GPL v2.
# Copyright © 2011 Gianpaolo Del Matto <www.phunsites.net>
# 
# r0.1 initial release 2011/12/09
# - simple selector with default action after timeout
#
# r0.2 2011/12/15
# - added limited GUI scripting functionality for MakeMKV
#
# r0.3 2011/12/16
# - added support to check for assistive device access
#	(code borrowed from http://www.macosxautomation.com)
# - added simple progress indicator while waiting for drive
#	do become available for access
#

# initialization
#
# true : show progress dialogs, false: hide progress dialogs
set verbose to true

# kindly borrowed from
# http://www.macosxautomation.com/applescript/uiscripting/index.html
# make sure that support for assistive devices is enabled
#
tell application "System Events"
	if UI elements enabled is false then
		tell application "System Preferences"
			activate
			set current pane to pane id "com.apple.preference.universalaccess"
			display dialog "This script requires access for assistive devices be enabled." &#038; return &#038; return &#038; "To continue, click the OK button and enter an administrative password in the forthcoming security dialog." with icon 1
		end tell
		set UI elements enabled to true
		if UI elements enabled is false then
			display dialog "This script cannot run while access for assistive devices is disabled." &#038; return &#038; "Exiting now." buttons {"OK"} with icon 2
			return "user cancelled"
		end if
	end if
end tell

# check if DVD Player or MakeMKV are already running
# if not, present a little menu, that allows to select
# which application should be run
#
if not appIsRunning("DVD Player") and not appIsRunning("MakeMKV") then

	with timeout of 3600 seconds
		display dialog "Please choose your desired action:" with title "Action for DVD" buttons {"Cancel", "play DVD", "rip DVD"} cancel button "Cancel" giving up after (5)
	end timeout
	if button returned of result is "rip DVD" then
		if verbose then display dialog "Starting MakeMKV" buttons {"OK"} giving up after 2
		tell application "MakeMKV" to activate
		repeat
			if application "MakeMKV" is running then exit repeat
			delay 5
		end repeat

	else if button returned of result is "Cancel" then
		return
	else
		if verbose then display dialog "Starting DVD Player" buttons {"OK"} giving up after 2
		tell application "DVD Player" to activate
		return
	end if

end if

# check again if MakeMKV is running
# this time, attempt to automate these steps:
# - automatically open the DVD as soon as the drive is ready for access
#
if appIsRunning("MakeMKV") then
	# now tell MakeMKV what to do
	tell application "System Events"
		tell process "MakeMKV"
			# in some rare cases, the menu bar items will stay "greyed out"
			# even if a DVD was inserted
			# the culprit: "AXEnabled" property of the menu will be TRUE even then,
			# although the menu items are not clickable
			# There seems to be no way to check, if they're actually active or inactive
			# However, as a workaround, sending CMD+O to fire up the "File - Open" dialog
			# seems to work, and yet: just opening and closing it will enable the menu bar
			#
			set _retval to false
			repeat until (_retval) is true
				try
					tell application "MakeMKV" to activate
					keystroke "o" using {command down}
					delay 1

					if (exists window 1) and (exists window 2) and (value of attribute "AXRoleDescription" of window 1) = "dialog" then
						click button "Cancel" of window 1
						set _retval to true
					end if
				end try
				delay 1
			end repeat

			# note on the dvd drive selection and menu handling:
			#
			# because we don't know the name of the DVD device,
			# we simply address it by the id of 'menu item 1'
			# so we're just selecting the first device found there.
			# we might have more than one DVD drive, but this is out of scope for now
			#
			# this script was initially triggered by inserting a new disc
			# thus we need to wait until the disc is initially read
			# while this is in progress, our 'Open disc' menu item will be disabled
			#
			set _retval to false
			repeat until (_retval) is true
				try
					repeat while (value of attribute "AXEnabled" of menu "Open disc" of menu item "Open disc" of menu "File" of menu bar item "File" of menu bar 1) is false
						get value of attribute "AXEnabled" of menu "Open disc" of menu item "Open disc" of menu "File" of menu bar item "File" of menu bar 1
						set counter to 5
						repeat while counter is greater than 0
							if verbose then display dialog "Waiting for dvd drive to become ready for use ..." with title "Please wait …" buttons {"" &#038; counter &#038; ""} giving up after 1
							set counter to counter - 1
						end repeat
					end repeat
					set _retval to true
				on error
					display dialog "error"
				end try
				delay 1
			end repeat

			# seems that the dvd drive is now ready for use, now try to load the disc
			#
			if verbose then display dialog "Trying to load DVD in MakeMKV now …" giving up after 1

			# now load the drive
			#
			tell application "MakeMKV" to activate
			click menu item 1 of menu 1 of menu item "Open disc" of menu 1 of menu bar item "File" of menu bar 1

			# now stay and wait until another window appears
			# this should be "completed" dialog at the end
			#
			repeat until ((exists window 1) and (exists window 2))
				delay 15
			end repeat

			# check the type of window 1, which should be a dialog
			# if so, let's close it and try to eject the disk
			#
			if (exists window 1) and (exists window 2) and ((value of attribute "AXRoleDescription" of window 1) = "dialog" or (value of attribute "AXRoleDescription" of window 1) = "standard window") then
				click button 1 of window 1

				click menu item "Eject disc" of menu 1 of menu bar item "File" of menu bar 1
			end if

		end tell
	end tell
end if

# func:appIsRunning
#	appName	: string : name of application (e.g. "DVD Player")
#
# helper to check if application is running or not
#
on appIsRunning(appName)
	tell application "System Events" to (name of processes) contains appName
end appIsRunning
</pre>
<p>This, as far as it goes, saves at least the additional button click to load the DVD in MakeMKV.<br />
However, there is one drawback after all &#8230;</p>
<p>While examining the MakeMKV GUI, I figured that the main panel was not recognized by UI Browser. It was just reported as <b>unknown (UI element #4)</b>. Unfortunately there was no obvious way to get access to the elements within that panel.<br />
This &#8211; as of today &#8211; effectively limits the use of GUI scripting, as it is not possible to interact with the elements within that panel.<br />
Otherwise, I&#8217;d be happy to sit down and write the part, which does auto-selection of the track elements according to some given criteria.</p>
]]></content:encoded>
			<wfw:commentRss>http://phaq.phunsites.net/2011/12/15/automating-makemkv-with-applescript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Make OS X run custom actions upon DVD insert</title>
		<link>http://phaq.phunsites.net/2011/12/11/make-os-x-run-custom-actions-upon-dvd-insert/</link>
		<comments>http://phaq.phunsites.net/2011/12/11/make-os-x-run-custom-actions-upon-dvd-insert/#comments</comments>
		<pubDate>Sun, 11 Dec 2011 10:44:39 +0000</pubDate>
		<dc:creator>gdelmatto</dc:creator>
				<category><![CDATA[OS X]]></category>
		<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://phaq.phunsites.net/?p=837</guid>
		<description><![CDATA[I&#8217;m currently ripping my complete DVD collection off to MKV (Matroska) format, so I can stream them across my home network. So I sought a way to have my OS X give me the choice to either start DVD Player or MakeMKV upon inserting a DVD. First I wrote a little AppleScript which gives me [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m currently ripping my complete DVD collection off to MKV (Matroska) format, so I can stream them across my home network.</p>
<p>So I sought a way to have my OS X give me the choice to either start DVD Player or <a href="http://www.makemkv.com/" target="_blank">MakeMKV</a> upon inserting a DVD.<br />
<span id="more-837"></span><br />
First I wrote a little AppleScript which gives me the choice. If I&#8217;m not taking any action, it will play the DVD automatically after 5 seconds, so it&#8217;s very similar to the default behaviour of OS X.</p>
<p>So just run Apple Script-Editor and store this code to a convenient location you like (usually it&#8217;s ~/Library/Scripts).</p>
<pre>
if not appIsRunning("DVD Player") and not appIsRunning("MakeMKV") then
	with timeout of 3600 seconds
		display dialog "Bitte wählen Sie gewünschte Aktion:" with title "Aktion für DVD" buttons {"Cancel", "DVD abspielen", "DVD rippen"} cancel button "Cancel" giving up after (5)
	end timeout
	if button returned of result is "DVD rippen" then
		display dialog "Starte MakeMKV" buttons {"OK"} giving up after 2
		tell application "MakeMKV" to activate
	else if button returned of result is "Cancel" then
		quit
	else
		display dialog "Starte DVD-Player" buttons {"OK"} giving up after 2
		tell application "DVD Player" to activate
	end if
end if

on appIsRunning(appName)
	tell application "System Events" to (name of processes) contains appName
end appIsRunning
</pre>
<p>Then go to system properties and select CDs &amp; DVDs properties. Beneath &#8220;When you a insert a Video-DVD&#8221; choose &#8220;Run Script&#8221; and locate the script file you created before.</p>
<p><a href="http://phaq.phunsites.net/files/2011/12/dvdaction1.jpg" rel="lightbox[837]"><img src="http://phaq.phunsites.net/files/2011/12/dvdaction1-300x119.jpg" alt="" width="300" height="119" class="aligncenter size-medium wp-image-838" /></a></p>
<p>From now on, you&#8217;ll be presented with a selection prompt. Doing nothing will automatically start the DVD Player, or the DVD Ripper, if you choose to do so.<br />
Quiet cool, isn&#8217;t it? <img src='http://phaq.phunsites.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p><a href="http://phaq.phunsites.net/files/2011/12/dvdaction2.png" rel="lightbox[837]"><img src="http://phaq.phunsites.net/files/2011/12/dvdaction2-300x96.png" alt="" width="300" height="96" class="aligncenter size-medium wp-image-839" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://phaq.phunsites.net/2011/12/11/make-os-x-run-custom-actions-upon-dvd-insert/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Shutting Speakers on OS X when Screen Saver runs</title>
		<link>http://phaq.phunsites.net/2011/12/02/shutting-speakers-on-os-x-when-screen-saver-runs/</link>
		<comments>http://phaq.phunsites.net/2011/12/02/shutting-speakers-on-os-x-when-screen-saver-runs/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 14:32:32 +0000</pubDate>
		<dc:creator>gdelmatto</dc:creator>
				<category><![CDATA[OS X]]></category>
		<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://phaq.phunsites.net/?p=780</guid>
		<description><![CDATA[Why for God&#8217;s sake would anyone even think about shutting speakers while the screen saver runs? Don&#8217;t these thingies provide an internal mute switch to stay quiet? Well, yes, most of the time, they do. Though in my case, I run that nice and decent System47 LCARS-style screen saver. And while it provides indeed a [...]]]></description>
			<content:encoded><![CDATA[<p>Why for God&#8217;s sake would anyone even think about shutting speakers while the screen saver runs?<br />
Don&#8217;t these thingies provide an internal mute switch to stay quiet?</p>
<p>Well, yes, most of the time, they do. Though in my case, I run that nice and decent <a href="http://www.mewho.com/system47/" target="_blank">System47</a> LCARS-style screen saver. And while it provides indeed a mute switch, it yet refuses to honor that flag and will always revert to non-muted operations. This drives me crazy, at least during the night time.</p>
<p>So here&#8217;s my solution to shut it quiet &#8212; really handy when I&#8217;m not along and forgot to turn volume down &#8230;<br />
<span id="more-780"></span><br />
The key to it lies with a small Automator script, which I hacked up and which you can <a href='http://phaq.phunsites.net/files/2011/12/Shut-Speakers-on-Screen-Saver.zip'>download here</a>.</p>
<p>It basically consists of an endless loop, which will sleep some time, wake up, check if the screen saver is running and mute the speakers if that&#8217;s the case.<br />
It will also unmute the speakers if the screen saver is not running, e.g. when you return to the work place.</p>
<p><a href="http://phaq.phunsites.net/files/2011/12/preview.png" rel="lightbox[780]"><img src="http://phaq.phunsites.net/files/2011/12/preview-300x114.png" alt="" width="300" height="114" class="aligncenter size-medium wp-image-783" /></a></p>
<p>So first download the file and extract it to your desktop.<br />
Then double click the file to import it to Automator.</p>
<p><a href="http://phaq.phunsites.net/files/2011/12/step1.png" rel="lightbox[780]"><img src="http://phaq.phunsites.net/files/2011/12/step1-300x125.png" alt="" width="300" height="125" class="aligncenter size-medium wp-image-785" /></a></p>
<p><a href="http://phaq.phunsites.net/files/2011/12/step2.png" rel="lightbox[780]"><img src="http://phaq.phunsites.net/files/2011/12/step2-300x90.png" alt="" width="300" height="90" class="aligncenter size-medium wp-image-786" /></a></p>
<p>You&#8217;ll end up with the script being added to your &#8220;Services&#8221; menu.</p>
<p><a href="http://phaq.phunsites.net/files/2011/12/step3.png" rel="lightbox[780]"><img src="http://phaq.phunsites.net/files/2011/12/step3-300x125.png" alt="" width="300" height="125" class="aligncenter size-medium wp-image-787" /></a></p>
<p>Now open up your control panel and go the the <strong>Users &amp; Groups</strong> preferences. Select your account and navigate to <strong>Startup Items</strong>.</p>
<p><a href="http://phaq.phunsites.net/files/2011/12/step4.png" rel="lightbox[780]"><img src="http://phaq.phunsites.net/files/2011/12/step4-300x226.png" alt="" width="300" height="226" class="aligncenter size-medium wp-image-788" /></a></p>
<p>Click the + icon to add a new startup item. Use Finder to navigate to the Library folder below your home directory and then locate the <strong>Shutting Speakers on Screen Saver</strong> automator script beneth the Services folder.</p>
<p><a href="http://phaq.phunsites.net/files/2011/12/step5.png" rel="lightbox[780]"><img src="http://phaq.phunsites.net/files/2011/12/step5-300x156.png" alt="" width="300" height="156" class="aligncenter size-medium wp-image-789" /></a></p>
<p>Note for OS X Lion Users: You may not see the Library folder in the first place due to restrictive defaults on Lion. If that&#8217;s the case, open a Terminal and type this command in there:</p>
<p><code><br />
chflags nohidden ~/Library<br />
</code></p>
<p>This will enable the Library folder to be seen within Finder.</p>
<p>Now select the <strong>Shutting Speakers on Screen Saver</strong>. It will be added to your startup item preferences.</p>
<p><a href="http://phaq.phunsites.net/files/2011/12/step6.png" rel="lightbox[780]"><img src="http://phaq.phunsites.net/files/2011/12/step6-300x226.png" alt="" width="300" height="226" class="aligncenter size-medium wp-image-790" /></a></p>
<p>The script will now run everytime after logon, so you won&#8217;t need to care about having the system muted or not.<br />
If you want to run it now without logoff/logon, just go to Finder menu and click on <strong>Shutting Speakers on Screen Saver</strong> on the Services submenu.</p>
<p>Enjoy the silence <img src='http://phaq.phunsites.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://phaq.phunsites.net/2011/12/02/shutting-speakers-on-os-x-when-screen-saver-runs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Print File Contents in Reverse Order (&#8220;reverse cat&#8221;)</title>
		<link>http://phaq.phunsites.net/2011/07/27/print-file-contents-in-reverse-order-reverse-cat/</link>
		<comments>http://phaq.phunsites.net/2011/07/27/print-file-contents-in-reverse-order-reverse-cat/#comments</comments>
		<pubDate>Wed, 27 Jul 2011 14:08:34 +0000</pubDate>
		<dc:creator>gdelmatto</dc:creator>
				<category><![CDATA[Perl]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://phaq.phunsites.net/?p=719</guid>
		<description><![CDATA[The &#8216;cat&#8217; utility serves it&#8217;s purpose print the content of a file at once. So do &#8216;more&#8217; and other tools as well. But they all do in &#8216;forward&#8217; mode only. To print a file in reverse order, at least some linux distros come with the &#8216;tac&#8217; command, which will do a &#8216;reverse cat&#8217;. But what [...]]]></description>
			<content:encoded><![CDATA[<p>The &#8216;cat&#8217; utility serves it&#8217;s purpose print the content of a file at once. So do &#8216;more&#8217; and other tools as well. But they all do in &#8216;forward&#8217; mode only.<br />
To print a file in reverse order, at least some linux distros come with the &#8216;tac&#8217; command, which will do a &#8216;reverse cat&#8217;.<br />
But what to do, if &#8216;tac&#8217; is missing?<br />
<span id="more-719"></span><br />
If you don&#8217;t want to go for an additional tool to compile and install, why not check out Perls abilities?</p>
<p>Here&#8217;s how to do it with a PIPE:</p>
<p><code><br />
[gianpaolo@localhost ~]$ cat filename | perl -e 'print reverse &lt;&gt;;'<br />
</code></p>
<p>You can also run it directly on a filename like this:</p>
<p><code><br />
[gianpaolo@localhost ~]$ perl -e 'print reverse &lt;&gt;;' -f filename<br />
</code></p>
<p>You can do it with &#8216;sed&#8217; as well:</p>
<p><code><br />
[gianpaolo@localhost ~]$ cat filename | sed -n '1!G;h;$p'<br />
[gianpaolo@localhost ~]$ sed -n '1!G;h;$p' filename<br />
</code></p>
<p>Personally I favor the Perl method as it&#8217;s easier to memorize, despite having more to type <img src='http://phaq.phunsites.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /><br />
Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://phaq.phunsites.net/2011/07/27/print-file-contents-in-reverse-order-reverse-cat/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Shell Scripting: How to easily convert UNIX timestamp into date format</title>
		<link>http://phaq.phunsites.net/2011/03/31/shell-scripting-how-to-easily-convert-unix-timestamp-into-date-format/</link>
		<comments>http://phaq.phunsites.net/2011/03/31/shell-scripting-how-to-easily-convert-unix-timestamp-into-date-format/#comments</comments>
		<pubDate>Thu, 31 Mar 2011 09:42:06 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Perl]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://phaq.phunsites.net/?p=588</guid>
		<description><![CDATA[When writing shell scripts (bash, sh, etc) maybe you had to work with POSIX/UNIX timestamps from time to time. While the serialized nature of the timestamp is great to work with for scripting, it&#8217;s easier for human beings to have them printed in date format. Before you start digging around using some fancy conversion in [...]]]></description>
			<content:encoded><![CDATA[<p>When writing shell scripts (bash, sh, etc) maybe you had to work with POSIX/UNIX timestamps from time to time.<br />
While the serialized nature of the timestamp is great to work with for scripting, it&#8217;s easier for human beings to have them printed in date format.</p>
<p>Before you start digging around using some fancy conversion in Perl, check out the &#8216;date&#8217; command first.<br />
<span id="more-588"></span><br />
Here&#8217;s a little snippet on how to do it on Linux:</p>
<p><code><br />
date -u --date="1970-01-01 1285250916 sec GMT"<br />
</code></p>
<p>This will convert your timestamp 1285250916 into it&#8217;s date representation of <strong>Thu Sep 23 14:08:36 UTC 2010</strong>.</p>
<p>As always, there&#8217;s slight variations with Linux and BSD userland. To achieve the same on OS X and FreeBSD (maybe other BSDs as well), here&#8217;s the appropriate command:</p>
<p><code><br />
date -j -f %s 1285250916<br />
</code></p>
<p>And for Perl lovers anyway, here is the Perl command <img src='http://phaq.phunsites.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p><code><br />
perl -e "print scalar localtime (1285250916)"<br />
</code></p>
<p>As such it&#8217;s very easy to capture the output using backticks and use it further on in your scripts. The date command comes in as a last resort especially if you&#8217;re working in a restricted environment where higher level languages such as Perl may be unavailable. Though one notices Perl is more versatile than the date command &#8211; the later having slight syntactical variations between distributions and vendors propably causing some headache. This opts for the use of Perl if you want to be more platform independent with your script.</p>
]]></content:encoded>
			<wfw:commentRss>http://phaq.phunsites.net/2011/03/31/shell-scripting-how-to-easily-convert-unix-timestamp-into-date-format/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>De-Scrambler for obfuscated PHP code</title>
		<link>http://phaq.phunsites.net/2010/12/15/de-scrambler-for-obfuscated-php-code/</link>
		<comments>http://phaq.phunsites.net/2010/12/15/de-scrambler-for-obfuscated-php-code/#comments</comments>
		<pubDate>Wed, 15 Dec 2010 00:41:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://phaq.phunsites.net/?p=230</guid>
		<description><![CDATA[Thinking about security risks of obfuscated PHP code found in some freely available PHP scripts and WordPress themes, I wrote a quick&#8217;n'dirty De-Scrambler. The De-Scrambler tries to reveal the source code behind obfuscated block like these: &#60;? eval(gzinflate(str_rot13(base64_decode(&#8216;DZe3DsTWEV &#8212;-shortened&#8212;- Z9//g8=&#8217;)))); ?&#62; The De-Scrabmler works on obfuscated blocks containing eval()&#8217;ed code created through gz_deflate(), base64_encode() and [...]]]></description>
			<content:encoded><![CDATA[<p>Thinking about <a href="http://phaq.phunsites.net/2010/12/15/obfuscated-php-code-in-wordpress-themes-or-php-scripts-may-be-a-security-hole/">security risks of obfuscated PHP code found in some freely available PHP scripts and WordPress themes</a>, I wrote a quick&#8217;n'dirty De-Scrambler.<br />
<span id="more-230"></span><br />
The De-Scrambler tries to reveal the source code behind obfuscated block like these:</p>
<p>&lt;? eval(gzinflate(str_rot13(base64_decode(&#8216;DZe3DsTWEV  &#8212;-shortened&#8212;-  Z9//g8=&#8217;)))); ?&gt;</p>
<p>The De-Scrabmler works on obfuscated blocks containing eval()&#8217;ed code created through gz_deflate(), base64_encode() and str_rot13() functions.</p>
<p>It&#8217;s very simple to use even for non-pro&#8217;s. Just copy-paste the scrambled text block into the form and let the De-Scrambler do the rest.</p>
<div align="center">
<h2><a href="http://phunsites.net/descrambler" target="_blank">Start PHP De-Scrambler</a></h2>
</div>
<p>Sample view of scrambled code in a WordPres Theme:</p>
<p><a href="http://phaq.phunsites.net/files/2010/12/wp_theme_editor.png" rel="lightbox[230]"><img src="http://phaq2.phunsites.net/wp-content/uploads/2010/12/wp_theme_editor-300x158.png" alt="wp_theme_editor" width="300" height="158" class="aligncenter size-medium wp-image-228" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://phaq.phunsites.net/2010/12/15/de-scrambler-for-obfuscated-php-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Trap Errors, Exit Codes and Line Numbers within a Bash script (and some output redirection, too)</title>
		<link>http://phaq.phunsites.net/2010/11/22/trap-errors-exit-codes-and-line-numbers-within-a-bash-script/</link>
		<comments>http://phaq.phunsites.net/2010/11/22/trap-errors-exit-codes-and-line-numbers-within-a-bash-script/#comments</comments>
		<pubDate>Mon, 22 Nov 2010 20:35:20 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Shells]]></category>

		<guid isPermaLink="false">http://phaq.phunsites.net/?p=177</guid>
		<description><![CDATA[A discussion today was about error handling in shell scripts, Bash in particular. Well, we all know about the usual knitpicks about error handling and the possible consequences in not doing so properly The most simplistic approach in error handling are of course control structures to check the return value: some arbitrary command if [ [...]]]></description>
			<content:encoded><![CDATA[<p>A discussion today was about error handling in shell scripts, Bash in particular.<br />
Well, we all know about the usual knitpicks about error handling and the possible consequences in not doing so properly <img src='http://phaq.phunsites.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /><br />
<span id="more-177"></span><br />
The most simplistic approach in error handling are of course control structures to check the return value:</p>
<pre>
some arbitrary command
if [ "$?" = "0" ]; then
   do something
else
   do something else
fi
</pre>
<p>Or even more simplistic:</p>
<pre>
some arbitrary command &amp;&amp; { do something; } || { do something else; }
</pre>
<p>There are more ways to do this. But they all have in common, that it is hard to trap and trace unknown errors, especially if the script runs unattended.<br />
If you want to do some logging and tracing, then you would need to implement a routine which you would need to add to each and every block, to ensure you don&#8217;t miss some particular important information.<br />
Even if it is a simple function for error reporting, let&#8217;s call it error_reporter, you would end up with something like this:</p>
<pre>
some arbitrary command
if [ "$?" = "0" ]; then
   do something
   error_reporter args
else
   do something else
   error_reporter args
fi
</pre>
<p>But sometimes it&#8217;s better to have an error handler, which is able to catch errors and do some special actions, while still allowing your script to continue within the normal flow. Even better if that particular error handler also catches and notifies upon yet-unknown and never discovered errors.</p>
<p>Let&#8217;s assume a script, which is trying to delete a directory. For the sake of this example, the directory MUST NOT exist, so the script effectively fails upon execution.<br />
We handle the error simply by checking on the non-zero exit code.</p>
<p>Please note: The following code serves as an example of bad script programming. Never (as in NEVER) try to delete something without checking for it&#8217;s existence first! You&#8217;ll find a proper code sample at the end of this article <img src='http://phaq.phunsites.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<pre>
#!/bin/bash

# try to delete non-existing directory
#
rmdir /ksdjhfskdfkshd
if [ "$?" = "0" ]; then
        echo "ok: directory deleted."
else
        echo "failed: directory not deleted."
fi
</pre>
<p>This script will try to delete the non-existing directory. As &#8216;rm&#8217; will not find it, it will return a non-zero exit status, leading to this program output:</p>
<pre>
$ bash test.sh
rm: /ksdjhfskdfkshd: No such file or directory
failed: directory not deleted.
</pre>
<p>So far, so good. The error was caught and nothing really bad happened, we even got kinda useful error message from the script itself.<br />
Now, let&#8217;s think about scripts, which usually run unattended, maybe invoked through cron.<br />
Any halfway serious admininstrator would at least try to capture the error output from cron by redirecto STERR and STDOUT to a logfile.</p>
<pre>
*/5 * * * *	root	/var/scripts/somescript &gt; /var/log/somescript.log 2&gt;&amp;1
</pre>
<p>But, to be serious, how often would you really check on these logfiles?</p>
<p>Of course, you can have cron configured to send you the script output after every run.<br />
If you use an output redirection as shown above, you could even write another script, which sends these logfiles to you.<br />
This is good enough, you&#8217;ll end up with dozens if not hundreds mostly useless emails, which you&#8217;ll most likely never ever get to read.</p>
<p>Wouldn&#8217;t it be great to have the script report any runtime errors to you by email, directly into a database or via SNMP traps, but only in the event of some real importance to look at?<br />
In this case, you&#8217;ll end up with error reports driven by occurence. So you KNOW that it&#8217;s important and some action needs to be performed.</p>
<p>Luckily enough Bash provides us with a very simple TRAP interface, which allows to run additional, event-driven code, upon occurence.<br />
We can trap nearly every thing, from EXIT to CTRL-C, over SIGNALS up to ERROR status (you&#8217;ll find more about this in the Bash info page).</p>
<p>To trap an ERROR status, we need two things: A trap handler and a trap command.<br />
The first is some code, which does any particular action, for example assemble error information and send it by email, while the trap command itself specifies, under what condition it needs to be invoked.</p>
<p>A trap handler could look something like this:</p>
<pre>
function my_trap_handler()
{
        MYSELF="$0"               # equals to my script name
        LASTLINE="$1"            # argument 1: last line of error occurence
        LASTERR="$2"             # argument 2: error code of last command
        echo "${MYSELF}: line ${LASTLINE}: exit status of last command: ${LASTERR}"

        # do additional processing: send email or SNMP trap, write result to database, etc.
}
</pre>
<p>To have the trap handler executed, you need to add a &#8220;trap&#8221; statement to the script. As we want the trap_handler to be invoked only upon a  command failure, we consider only the ERR trap, which catches non-zero exit codes only.</p>
<pre>
trap my_trap_handler ${LINENO} ${$?}' ERR
</pre>
<p>Let&#8217;s have a look at the completed script now.<br />
To demonstrate how accurately the trap handler works, I added some further commands. These commands have been designed so that they WILL fail for the sake of documentary purposes.</p>
<pre>
#!/bin/bash

# trap handler: print location of last error and process it further
#
function my_trap_handler()
{
        MYSELF="$0"               # equals to my script name
        LASTLINE="$1"            # argument 1: last line of error occurence
        LASTERR="$2"             # argument 2: error code of last command
        echo "${MYSELF}: line ${LASTLINE}: exit status of last command: ${LASTERR}"

        # do additional processing: send email or SNMP trap, write result to database, etc.
}

# trap commands with non-zero exit code
#
trap 'my_trap_handler ${LINENO} $?' ERR

# let's do some rubbish
#
rm /ksdjhfskdfkshd
if [ "$?" = "0" ]; then
        echo "ok: directory deleted."
else
        echo "failed: directory not deleted."
fi

# next is line 30
format c:                       # ;-)

# next is line 33
ls /fdkjhfskdhfks
</pre>
<p>This sample code will result in the following output at runtime. I added the line numbers in front on my own for better illustration.</p>
<pre>
$ bash test.sh
1:  rm: /ksdjhfskdfkshd: No such file or directory
2:  test3.sh: line 22: exit status of last command: 1
3:  failed: directory not deleted.
4:  test3.sh: line 30: format: command not found
5:  test3.sh: line 30: exit status of last command: 127
6:  ls: /fdkjhfskdhfks: No such file or directory
7:  test3.sh: line 33: exit status of last command: 1
</pre>
<p>Now, the first line of output shows the error thrown by the &#8216;rm&#8217; command.<br />
The second line shows the output from the trap handler, stating exactly WHERE the error occured (test.sh / line 22 / last exit status).<br />
The third line shows the output of the local error handling routine.<br />
Line four gives us the &#8220;format&#8221; command not found, while line five is the message from the trap handler.<br />
Line six and seven are the &#8220;ls&#8221; for the non-existing directory and the trap handler message corresponding to it.</p>
<p>Looking into this outline it quickly becomes clear, that a trap handler can help us a lot in event-driven debugging with just adding a few lines to existing scripts without tampering with existing error handling code.<br />
This script design even permits you to track and trace errors on single-line commands, which you almost never believed to fail.<br />
Even if they fail one day due to unlikely events, you can at least point out WHERE it failed, which makes debugging a lot faster and easier.</p>
<p>And now, finally, the completed script code, as any decent script writer should be propably doing it using some pre-action checking as well.</p>
<pre>
#!/bin/bash

# trap handler: print location of last error and process it further
#
function my_trap_handler()
{
        MYSELF="$0"               # equals to my script name
        LASTLINE="$1"            # argument 1: last line of error occurence
        LASTERR="$2"             # argument 2: error code of last command
        echo "${MYSELF}: line ${LASTLINE}: exit status of last command: ${LASTERR}"

        # do additional processing: send email or SNMP trap, write result to database, etc.
}

# trap commands with non-zero exit code
#
trap 'my_trap_handler ${LINENO} $?' ERR

# we need to process the DIRECTORY at /ksdjhfskdfkshd
#
my_directory=/ksdjhfskdfkshd

# test if the directory exists
#
echo -n "check if directory exists: '${my_directory}': "

if [ -d "${my_directory}" ]; then
        echo "ok."

        # try to delete the file
        #
        rmdir "${my_directory}"

        # try to handle delete failure (exit != 0)
        #
        if [ "$?" = "0" ]; then
                echo "ok: directory deleted."
        else
                echo "failed: directory not deleted."
        fi
else
        echo "failure, directory does not exist or is not a directory."
fi

# we're done
#
exit
</pre>
<p>This would result in the following output. The trap is completely circumvented by testing the directory for it&#8217;s existence before deleting it.</p>
<pre>
$ bash test.sh
check if file exists: '/ksdjhfskdfkshd': failure, directory does not exist or is not a directory.
</pre>
<p>One more thing to consider is what happens, if a trap is caught within a control structure block (IF, WHILE, etc).</p>
<p>To illustrate this, I create the directory I wanted to delete, so the script will dive into the IF-THEN-ELSE-FI block.</p>
<pre>
$ mkdir /ksdjhfskdfkshd
</pre>
<p>I then changed the &#8220;rmdir&#8221; command within the script to &#8220;rmdiir&#8221; (misspelled), so it WILL fail upon execution.<br />
Please note the script output we get this time:</p>
<pre>
$ bash test.sh
check if file exists: '/ksdjhfskdfkshd': ok.
test.sh: line 34: rmdiir: command not found
test.sh: line 45: exit status of last command: 127
failed: directory not deleted.
</pre>
<p>While Bash itself states the misspelled command being on line 34, the trap catches the error on line 45.</p>
<p>Now, why is this?</p>
<p>The reason for this is very simple: Any control structure is regarded as some sort of multi-line command within the script.<br />
So when the trap catches the erronous command on line 34, it sees it&#8217;s origin on line 45 because the &#8220;IF-THEN-ELSE-FI&#8221; clause ends on line 45.</p>
<p>The same happens if you use any other control structure.</p>
<p>The trap in this case is only capable of outlining the &#8220;general direction&#8221; to where the error happened, but it cannot pin-point to it.<br />
So it&#8217;s still recommended to also capture the script output, either by redirecting the script output manually from the shell, or more elegantly by adding some lines to the script, which always redirect the output (STDERR and STDOUT) to a logfile automatically.</p>
<p>In the end, the trap handler could be setup to send and email using both information from the intercepted trap and the logfile.</p>
<p>So the final script may look like this:</p>
<pre>
#!/bin/bash

# initialize upon startup
#
my_temp_dir=`mktemp -d /tmp/test.XXXXXX`		# we want a unique temp dir
my_log_file=${my_temp_dir}/output.log
my_out_pipe=${my_temp_dir}/output.pipe

# initialize output redirection
#
mkfifo ${my_out_pipe}                                   # we need a FIFO for the output pipe
exec 3&gt;&amp;1                                               # assign a new file descriptor 3 to STDOUT
tee ${my_log_file} &amp;3 &amp;               # background redirect file descriptor 3 throught the FIFO
tee_pid=$!                                              # store the PID for 'tee'
exec 2&gt;&amp;1 &gt; ${my_out_pipe}                              # redirect STDERR and STDOUT to the output pipe

# do some final cleanup upon exit
#
function my_exit_handler()
{
     exec 1&gt;&amp;3 3&gt;&amp;-                                    # restore file descriptors
     wait ${tee_pid}                                   # wait for 'tee' to exit

     # remove temp dir upon exit
     #
     #[ -d ${my_temp_dir} ] &amp;&amp; rm -rf ${my_temp_dir}
}

# trap handler: print location of last error and process it further
#
function my_trap_handler()
{
        MYSELF="$0"               # equals to my script name
        LASTLINE="$1"            # argument 1: last line of error occurence
        LASTERR="$2"             # argument 2: error code of last command
        echo "script error encountered at `date` in ${MYSELF}: line ${LASTLINE}: exit status of last command: ${LASTERR}"

        # do additional processing: send email or SNMP trap, write result to database, etc.
	#
	# let's assume we send an email message with
	# subject: "script error encountered at `date` in ${MYSELF}: line ${LASTLINE}: exit status of last command: ${LASTERR}"
	# with additional contents of ${my_log_file} as email body
}

# trap commands with non-zero exit code
# trap script EXIT
#
trap 'my_trap_handler ${LINENO} $?' ERR
trap 'my_exit_handler' EXIT

# we need to process the DIRECTORY at /ksdjhfskdfkshd
#
my_directory=/ksdjhfskdfkshd

# test if the file exists
#
echo -n "check if file exists: '${my_directory}': "

if [ -d "${my_directory}" ]; then
	echo "ok."

	# try to delete the file
	#
	rmdir "${my_directory}"

	# try to handle delete failure (exit != 0)
	#
	if [ "$?" = "0" ]; then
	        echo "ok: directory deleted."
	else
	        echo "failed: directory not deleted."
	fi
else
	echo "failure, directory does not exist or is not a directory."
fi

# we're done
#
exit
</pre>
<p>To conclude this: Adding some further logic to a script using output redirection and traps adds some great debugging aid, especially when it comes to unknown and yet-undiscovered errors.<br />
The implementation requires just a few additional lines to work with any script and will save countless hours worth of debugging.<br />
Also, the sample trap handler presented herein can be extended to do virtually anything, from adding additional information like the environment, to submitting errors into a MySQL database, sending SNMP traps, or whatever you could imagine.</p>
]]></content:encoded>
			<wfw:commentRss>http://phaq.phunsites.net/2010/11/22/trap-errors-exit-codes-and-line-numbers-within-a-bash-script/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>No &quot;sleep&quot; command for batch files? Make it a choice!</title>
		<link>http://phaq.phunsites.net/2007/05/05/no-sleep-command-for-batch-files-make-it-a-choice/</link>
		<comments>http://phaq.phunsites.net/2007/05/05/no-sleep-command-for-batch-files-make-it-a-choice/#comments</comments>
		<pubDate>Sat, 05 May 2007 18:35:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[DOS]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://phaq.phunsites.net/2007/05/05/no-sleep-command-for-batch-files-make-it-a-choice/</guid>
		<description><![CDATA[I just trapped myself while hacking up a batch file. Used to shell scripting I wanted to add a delay to the batch using &#8220;sleep&#8221;. Dough! Bad Idea! Bad command or filename. Smash your head here to continue {(x)}! So I winded up my memories from stoneage. Wasn&#8217;t there the choice command!? Yeah, after some [...]]]></description>
			<content:encoded><![CDATA[<p>I just trapped myself while hacking up a batch file.<br />
Used to shell scripting I wanted to add a delay to the batch using &#8220;sleep&#8221;.</p>
<p>Dough! Bad Idea! Bad command or filename. Smash your head here to continue {(x)}!<br />
<span id="more-92"></span><br />
So I winded up my memories from stoneage. Wasn&#8217;t there the choice command!?</p>
<p>Yeah, after some lurking around with the &#8216;/?&#8217; feature I had stuck it together:</p>
<pre>choice /c 1 /d 1 /t 1 &gt; nul</pre>
<p>While</p>
<ul>
<li>&#8220;/c 1&#8243; sets the choice values (1 is my value)</li>
<li>&#8220;/d 1&#8243; sets the default choice value (which is 1 from above)</li>
<li>&#8220;/t 1&#8243; sets the timeout to 1 second (or whatever is appropriate)</li>
<li>&#8220;&gt; nul&#8221; means the same as &#8220;&gt;/dev/null&#8221;: send output to nirvana (notice there being only one &#8216;l&#8217; however)</li>
</ul>
<p>Of course this may be bothersome to type if you use it often, so a &#8220;batch function&#8221; may be better, especially when you need other batch tricks to get around DOS command limitations (lazy man&#8217;s approach: create a second batch file for it).</p>
<pre>
@echo off

rem *******************
rem check args
rem *******************

:checkargs

if "%1/" == "func/" goto callfunc
goto main

:_checkargs

rem *******************
rem call functions
rem *******************

:callfunc
 shift

 rem we could do "goto %1" instead
 rem if there is a lot of functions
 if "%1/" == "sleep/" goto sleep

 goto exit

:_callfunc

rem *******************
rem function sleep
rem *******************

:sleep
 shift

 choice /c 1 /d 1 /t %1 &gt; nul

 goto exit

:_sleep

rem *******************
rem main body
rem *******************

:main
 echo hello, going to sleep now
 call %0 func sleep 1

 echo sleep is over, good bye

 goto exit

:_main

rem *******************
rem exit handler
rem *******************

:exit
 rem if there is anything left to do, do it now.

:_exit</pre>
]]></content:encoded>
			<wfw:commentRss>http://phaq.phunsites.net/2007/05/05/no-sleep-command-for-batch-files-make-it-a-choice/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

