makkintosshu's Journal [entries|friends|calendar]
makkintosshu

[ website | My Website ]
[ userinfo | scribbld userinfo ]
[ calendar | scribbld calendar ]

A realpath Implementation in Bash [19 Feb 2012|02:48pm]

I was recently informed of an issue with the in-development version of trash (one of the utilities in tools-osx) that required using an absolute path internally instead of a relative path. In most languages one can just run a path through realpath() to get the absolute path for a relative path, but bash (which trash was developed in) doesn’t have an equivalent. Many people suggest readlink, but it’s generally only included in Linux distributions, so BSD-based operating systems (incl. Mac OS X) are a bit out of luck.

Fortunately, it’s quite easy to emulate using pwd, but there is a bit of extra work that must be done. I found a good, portable example, but it still wasn’t quite up to my standards. I’ve simplified & improved it and the result is as follows:

function realpath()
{
	local success=true

	# start with the file name (sans the trailing slash)
	local path="$1"
	path="${path%/}"

	# get the basename of the file (ignoring '.' & '..', because they're really part of the path)
	local file_basename="${path##*/}"
	if [[ ( "$file_basename" = "." ) || ( "$file_basename" = ".." ) ]]; then
		file_basename=""
	fi

	# extracts the directory component of the full path & attempt to change to it
	local directory="${path%$file_basename}"
	if [ "$directory" ]; then
	  if ! cd "$directory" &>/dev/null ; then
	  	success=false
	  fi
	fi

	if $success; then
		# does the filename exist?
		if [[ ( ! -z "$file_basename" ) && ( ! -e "$file_basename" ) ]]; then
			success=false
		fi

		# get the absolute path of the current directory & change back to previous directory
		local abs_path="$(pwd -P)"
		cd "-" &>/dev/null

		# Append base filename to absolute path
		abs_path="${abs_path}/${file_basename}"

		# output the absolute path
		echo "$abs_path"
	fi

	$success
}

Here’s a simple example of its usage:

relative_path="~/Desktop/"
absolute_path="$(realpath "$relative_path")"
if [ $? -eq 0 ]; then
	echo "absolute_path = $absolute_path"
else
	echo "'$relative_path' does not exist!"
fi

I have also tossed together a realpath tool which wraps around this implementation if you would like to install it for use in multiple scripts/tools. Feel free to download it from the development page or get the source code on GitHub. It’s released under a BSD license.

post comment

Environment Variables in NewtonScript and NEWT/0 [22 Jan 2012|03:37pm]

To expand upon my previous post demonstrating how to access command line arguments (ARGV) in NewtonScript in NEWT/0, I’ll demonstrate how to access environment variables. Command line arguments are only the beginning for writing command line tools as you often need to access environment variables as well. In some situations, like running a script as a CGI in your favorite HTTP server software, environment variables are really your only way to receive input from the outside world.

After digging through the NEWT/0 source code again, it appeared that I could again use GetGlobalVar(), but this time with the '_ENV_ object literal, but it didn’t seem to have anything useful in it, certainly not any environment variables. So, back to the source code I went and discovered that NEWT/0 implements a custom global function GetEnv(), like the getenv() equivalent in C, accepts a string for the environment variable name and returns the value stored in said environment variable.

To get the PATH environment variable, for example:

#!/usr/bin/env newt

Print("PATH:" && GetEnv("PATH") && "\n");

Or a basic “hello world” CGI that also echoes the query string:

#!/usr/local/bin/newt

Print("Content-Type: text/plain\n\n");

Print("Hello world!\n\n");
Print("QUERY_STRING:" && GetEnv("QUERY_STRING") && "\n");

I must thank NEWT/0’s developer, Makoto Nukui, for including all this functionality!

post comment

Command Line Arguments in NewtonScript and NEWT/0 [21 Jan 2012|11:19pm]

Still being a daily Newton user as well as a developer, I’ve always wanted to learn NewtonScript. I’ve got a PowerMac 9500 that’s been configured for Newton OS development for quite some time and I’ve got a couple projects in mind, but I just never seem to get around it.

I’ve also had NEWT/0, an open source, cross-platform NewtonScript interpreter, installed for a while. Since it can run NewtonScript scripts from the command line like any other interpreter, I decided I’d like to know if it was possible to get the command line arguments from NewtonScript so I could eventually write some local scripts to get myself familiar with the syntax & functions (therefore less of a learning curve when I finally get around to writing some actual Newton packages). After a point in the right direction from Matthias Melcher and a lot of digging through the NEWT/0 source code, I finally figured out how to do so.

Here’s a quick NewtonScript script that can be run through NEWT/0 to print out the command line arguments you pass to it:

#!/usr/bin/env newt

Print("'_ARGV_ exists? ");
if GlobalVarExists('_ARGV_) then Print("Yes.\n") else Print("No.\n");

foreach slot, value in GetGlobalVar('_ARGV_) do Print(slot && ":"
&& value && "\n");

I doubt there are many, if any, out there that are interested in doing this, but—who knows?—maybe somebody else will start scripting in NewtonScript too. (Expect to see some more NewtonScript-related news around here in the future.)

post comment

Twitter Statuses Badge 0.7.1 Released [16 Aug 2011|03:45pm]

Or, this should’ve been done nine months ago.

When I released v0.7 of my Twitter Statuses JavaScript Badge back in November of last year, it was right around the time that Twitter was rolling out their new ‘snowflake’ status ID generator which was going to have some implications for languages such as JavaScript. Unfortunately, I didn’t become aware of this until I started seeing random issues with status IDs a couple months later. More unfortunately, I’m only getting around to applying the minor tweak to fix this, and a minor issue with applying the ‘last’ class when there’s only one LI element, now.

Without further ado, I present v0.7.1! Please accept my apologies for sitting on this issue for so long and let me know if you have any questions, comments, or feature requests. Also, the source code is on GitHub.

FYI – I started developing a major update back in March, including a few frequently requested features. Hopefully I’ll get that polished up sometime this year.

post comment

tools-osx 2011-06-02 [02 Jun 2011|12:25pm]

I’ve updated my collection of Mac OS X command line tools with improvements to the trash tool:

  • trash can now list trash contents across all volumes (with a disk usage total) as well as empty the trash (including a secure empty option; both emptying operations require confirmation).

Note: Obviously, the new version of trash is now destructive. I have tested and use this myself, but I cannot guarantee it won’t securely erase your entire hard drive if it encounters some odd edge case and I cannot be held responsible for that. So, use at your own risk and keep backups!

Go download them all (clipcat, eject, swuser, and trash) or get the source code on github!

post comment

sde_newsletter v0.5 [28 Mar 2011|09:15pm]

I’ve got a very minor update to the sde_newsletter Textpattern plug-in. v0.5 word-wraps HTML & text content in message/part bodies to 78 characters (if possible) to prevent hard wrapping at 998 characters which tends to badly break HTML content.

The sde_newsletter plug-in helps build HTML, text, or multipart email messages from Textpattern pages (although, technically, you can use any web-facing source HTML & text). It’s straightforward and very powerful when paired with newsletter/mailing list software.

Update: I discovered a minor bug parsing page title from HTML if the TITLE element contains line breaks. This has been resolved in v0.5.1.

post comment

tools-osx 2011-02-25 [25 Feb 2011|12:50pm]

There’s been a small addition to my collection of Mac OS X command line tools:

  • swuser gives you control of Mac OS X’s Fast User Switching from the command line, including options for switching to login window, user by name, or user by ID. Unfortunately, it’s not compatible with screen.

Go download them all (clipcat, eject, swuser, and trash) or get the source code on github!

post comment

An AppleScript to Invert the Display in Grayscale (And Another to Revert) [17 Dec 2010|12:57pm]

I’ve been doing a lot of early morning coding in bed, and have found that the only way I can do so without killing my eyes is to select “Use grayscale” as well as “White on Black” in the Universal Access preferences pane in System Preferences. This gives me a far more comfortable, inverted grayscale display. Unfortunately, it’s annoying and painful to initially set when my eyes are at their most sensitive.

I’ve modified a script posted on Apple Discussions to enable grayscale to also invert the display1 and saved it as a run-only application named Invert Display.app:

tell application "System Preferences" to activate
delay 1
tell application "System Events"
	tell process "System Preferences"
		click the menu item "Universal Access" of the menu "View" of menu bar 1
		click the radio button "Seeing" of the first tab group of window "Universal Access"
		if value of (checkbox "Use grayscale" of tab group 1 of window "Universal Access") is 0 then
			click the checkbox "Use grayscale" of tab group 1 of window "Universal Access"
		end if
		-- click the radio button "White on Black" of tab group 1 of window "Universal Access"
	end tell
	key code 28 using {control down, option down, command down}
end tell
tell application "System Preferences" to quit

Naturally, I also created another to restore the settings and named it Restore Display.app:

tell application "System Preferences" to activate
delay 1
tell application "System Events"
	tell process "System Preferences"
		click the menu item "Universal Access" of the menu "View" of menu bar 1
		click the radio button "Seeing" of the first tab group of window "Universal Access"
		if value of (checkbox "Use grayscale" of tab group 1 of window "Universal Access") is 1 then
			click the checkbox "Use grayscale" of tab group 1 of window "Universal Access"
		end if
		-- click the radio button "Black on White" of tab group 1 of window "Universal Access"
	end tell
	key code 28 using {control down, option down, command down}
end tell
tell application "System Preferences" to quit

I just launch them from Spotlight as needed. It’s a little distracting to see System Preferences launch and do it’s thing, but far easier than doing it myself when my eyes are being seared out of their sockets.

1 – Note that I’ve left the line for selecting the “White on Black” radio button in the script, but commented out, in case someone can catch the reason it throws an error. Since I’m in the preference pane anyway, it seems silly to use key code, plus I’d rather be able to verify it’s actually selected (like I do with the checkbox) so I’m not blindly toggling.

post comment

tools-osx 2010-12-08 [09 Dec 2010|12:27pm]

I’ve got a new release of my collection of Mac OS X command line tools for you, including:

  • trash correctly increments filenames (à la Finder) if the same filename already exists in your Trash instead of complaining that the file already exists. It also has a teensiest bit more logic regarding trash on the boot volume vs. other volumes.
  • eject now supports ejecting mounted network volumes and includes a -f option to force a stubborn volume to eject (to be used only in extreme cases).
  • clipcat is a new addition, submitted by David Kendal, which allows printing & concatenating of Text Clippings!

Go ahead and download them or grab the source code on github!

post comment

tntk Command Line Newton Compiler [24 Nov 2010|06:13pm]

Yesterday, Eckhart Köppen announced that he’s started piecing together a command line Newton compiler named tntk, based on NEWT/0 & DCL:

So far my experiments are actually quite successful, and it seems that developing Newton applications with just a text editor is not that impractical. […] Some things are still missing for developing larger apps, like the ability to split the code into multiple source files, and a way to embed resources into the final package, but for simple applications (and even auto parts), we might have a way forward.

This is nowhere as ambitious as Matthias Melcher’s DyneTK project, but maybe good enough to get people interested in a bit of Newton hacking.

It’s not really far enough along for a release yet, but you can peek at the Subversion repository if you’re so inclined.

I have a PowerMac 9500 configured for Newton development purposes, among others, but it’s inconvenient at best when I’m actually inspired to do any Newton development. As Eckhart alludes to, dealing with Mac NTK’s binary files w/resource forks in version control is a major pain.

[Via NewtonTalk]

post comment

Twitter Statuses Badge V0.7 Released [11 Nov 2010|03:06am]

I’ve just released Twitter Statuses JavaScript Badge v0.7 which includes the following improvements:

  1. Support for searches as or the usual individual user’s statuses.
  2. Now using John Gruber’s Improved Liberal, Accurate Regex Pattern for Matching URLs
  3. More flexible adding of classes (incl. a new ‘reply’ class).
  4. The examples (yes, there’s a new one for search) use purely CSS rendering (no images).

And, here’s the search example:

Drop me a line if you have any questions, comments, improvements, or feature requests. I have a few more features planned for the next release.

post comment

Save the Xserve [09 Nov 2010|11:04pm]

It is our goal to make Apple recognize the breadth of users who deploy and rely on XServe systems running Mac OS X Server.

As a Newton user, I can tell you that no amount of petition signing is likely to bring back an Apple product from discontinuation, but it can’t make matters worse.

[Via Macintosh-Admin]

post comment

An Open Letter to Apple on Server Technologies [09 Nov 2010|10:46pm]

Dave Schroeder of UW-Madison and MacEnterprise:

Apple may not be an enterprise company, but Apple has long been an education company. As I look around campus now, this is clearer than ever. Today, many academic institutions have mirrored successful and established enterprise practices to provide robust, supportable, and cost-effective IT solutions. This means that running Mac OS X Server on a Mac Pro or Mac mini is not an option at an enterprise level. Virtualization is an option, and it doesn’t require Apple to develop or support any hardware. Please allow us to keep supporting your users.

post comment

Xserve, Your Day Has Come [05 Nov 2010|05:03pm]

As of today, the Xserve’s days are officially numbered. 87, to be exact. Come January 31st, 2011, Apple will no longer be selling Xserves.1 What a shame.

As the transition guide (PDF; linked to from the Xserve Resources page) explains, the two options going forward will be the Mac mini with Snow Leopard Server and the Mac Pro with Snow Leopard Server. To me, the gap seems painfully wide, with the following completely lost:

  • A powerful 1U option. Yes, you can fit 2+ Mac mini servers in 1U, but that’s not always the correct solution, nor will it yield the same raw processing throughput. Only being able to fit two Mac Pros in a whopping 12U of rack space is an astounding waste of space unless you actually need the internal storage & PCI Express expansion.
  • Hot swappable internal storage. I won’t miss the price tag of Apple’s drive modules, that’s for sure, but they did an excellent job of ensuring they were actually enterprise-grade. It’s slightly painful to think that both their server options will require a power down and to be pulled out of the rack2 just to swap a drive.
  • Redundant power supplies. I’m all for the lower power consumption of the Mac minis and Mac Pros, but the fact that Apple will have no server hardware that can be gracefully transitioned between power sources is very disappointing for those needing high availability.
  • Lights-Out Management. I personally don’t use LOM, and I frequently hear complaints about Apple’s LOM implementation, but the number of times I could’ve used it and not had to send someone to the server room (or drive in myself) is way up there. So, not even having it as an option is an additional downer. Maybe someday the Mac Pro will get LOM.

That said, the Mac Pro is a far more formidable piece of hardware than the Xserve, and the pricing of the Mac Pro with Snow Leopard Server, much like the Mac mini with Snow Leopard Server, is pretty much just throwing in a copy of Snow Leopard Server. Also, as Brian Stucki of Macminicolo.net put it on Twitter, “WAY too many small business put money into [an Xserve] when a Mac mini would have been perfect.”

It’s clear that Apple is saying goodbye to “Enterprise” and honing in on the SMB market.

1 Of course, there may be some old stock available through Apple Specialists and Apple Authorized Resellers.

2 If you have two Mac Pros on a shelf in a four-post rack, you can probably, depending on the positioning of side panels & cross-members, pull the side off of one of them to swap drives. Pain in the ass, though.

post comment

Regular Expressions in Bash (and Alternatives) [03 Nov 2010|12:21pm]

While cleaning up some old bash code and preparing tools-osx for release, I happened across a very useful bit of information: bash does support regular expressions! Well, at least bash 3.0 and newer do.

I first learned regular expressions in Perl, so I’ve pined for =~ in other scripting languages ever since. With bash, I, like most others, get by most of the time by piping things through grep for matching and sed for replacements, but the bane of my existence has always been capturing groups (capturing parentheses).

For example, let’s say we want to grab just the volume name out of a path like /Volumes/Macintosh HD/Users/Shared/, the following regular expression would be perfect for that:

^/Volumes/([^/]+)

That says match a string that starts with “/Volumes/” followed by one or more characters that are not “/” (capturing the one or more characters that are not “/”). So, if we were to match that against the aforementioned example path, it would capture:

Macintosh HD

Well, now I know that you can do this using bash 3.0+‘s built-in regular expressions support:

if [[ "/Volumes/Macintosh HD/Users/Shared/" =~ ^/Volumes/([^/]+) ]]; then
	vol="${BASH_REMATCH[1]}"
fi

Very straightforward for those who are familiar with regular expressions. However, it took my a while to get that to even work. Why? I assumed that I needed to quote the regular expression (in bash quoting is extremely important). The first tutorial I was going by pulled the regex from command line input and used it from a variable, so that offered little evidence for or against quoting the regular expression, but another that I found clearly was quoting the regular expression. Eventually I read the comments on the latter tutorial and there were some that found the regular expression worked in single quotes and some found that it had to be left unquoted.

For me, on Mac OS X 10.5 Leopard, bash regular expressions have to be left unquoted.

Note: bash 3.0+‘s built-in regular expressions are, like grep -e or egrep, POSIX extended regular expressions, not full Perl-compatible regular expressions, so make sure you understand the differences in syntax.

So, now comes the big caveat with all of this new found power and why it’s taken so long for me to discover it: bash 3.0 and newer have only started becoming common in the last few years, so it’s not widely supported yet. I looked through the Mac OS X source code and found that only Mac OS X 10.5 Leopard and 10.6 Snow Leopard have included a version of bash newer than version 3.0. Mac OS X 10.4 Tiger (including 10.4.11) and earlier all had bash 2.05 or earlier. So, you should really only use bash’s built-in regular expression support if you know the environment will have version 3.0 or newer.

I know, it certainly dashed my hopes a bit too.

In Which We Come to Understand an Alternative

However, all is not lost, there is a rudimentary alternative in read. It’ll never be as powerful as regular expressions, but it can allow simple captures like the example discussed above. Let me just throw you into the deep end and see if I can then explain how to swim.

Again, here’s that bash regular expression code snippet I came up with to parse the volume name out of a path:

if [[ "/Volumes/Macintosh HD/Users/Shared/" =~ ^/Volumes/([^/]+) ]]; then
	vol="${BASH_REMATCH[1]}"
fi

And here’s that same capture using read:

IFS=/ read -r -d '' _ _ vol _ <<< "Volumes/Macintosh HD/Users/Shared/"

Wow, it’s certainly more compact, but it doesn’t look like it contains much actual functionality, right? Just a couple switches and some underscores.

Let’s step through it, argument by argument:

  1. IFS=/ – Characters found in $IFS are word delimiters, so we’re setting our delimiter to “/”.
  2. read – Well, that’s the read command we’re calling to pull all this off.
  3. -r – Specify “raw” input (no backslash escaping).
  4. -d '' – Read until we hit ‘’ (an empty string) instead of a newline (so, essentially, read the entire input).
  5. _ _ vol _ – This is confusing part, this is actually where we tell read which variable to store each matching field in. Let’s break it down further:
    1. _ – The first character of our input string is a “/” (and so is our delimiter), so the first field is going to match an empty string (everything between the start and the first “/”, i.e. nothing), so we’ll just dump that in $_ to discard it.
    2. _ – The second match is going to be “Volumes” (everything between the first “/” and the second “/”), but we don’t care about that either, so discard it into $_ as well.
    3. vol – The third match (everything between the second “/” and third “/”) is what we’re actually looking for (the volume name), so we’ll store that in $vol.
    4. _ – The fourth match (and all further matches; everything between the third “/” and fourth “/”, and so on, and so on) are also nothing we care about, so also toss them into $_.
  6. <<< – This is a bash “here string” operator, it indicates that the following string be sent as standard input to the command.
  7. "Volumes/Macintosh HD/Users/Shared/" – This is the string we want to run through read to capture from.

Putting it back together a bit, we’d have something like this:

  1. IFS=/ – Split on the “/”.
  2. read -r -d '' _ _ vol _ – Store the 3rd field in $vol.
  3. <<< "Volumes/Macintosh HD/Users/Shared/" – From the string “Volumes/Macintosh HD/Users/Shared”.

And, just like the regular expression code, we end up with the following match stored in $vol:

Macintosh HD

Okay, you may have caught on that that read example was not actually the exact same capture as the regular expressions was, here’s why: the string doesn’t have to start with “/Volumes/”. We could’ve matched against “/Users/Shared/” and it would’ve captured “Shared”. That’s not going to cut it!

Fortunately, we could just wrap the call to read with a string comparison of the first zero through nine characters of the path name against “/Volumes/”, as so:

path="Volumes/Macintosh HD/Users/Shared/"
if [ "${path:0:9}" = "/Volumes/" ]; then
	IFS=/ read -r -d '' _ _ vol _ <<< "$path"
fi

Not so scary now, I hope, and far more backwards compatible with older versions of bash.

If you’re looking to capture from a string that can be reasonably split on a delimiter, like we did with the “/”, read is an excellent alternative to regular expressions (esp. when paired with other string comparisons). That said, if you know you can rely on having bash 3.0+, by all means, use the regular expressions!

post comment

Announcing tools-osx [27 Oct 2010|12:39am]

Ever since Mac OS X was released, I’ve found myself working via the command line more and more every year. While there are some native commands like open, pbcopy, and pbpaste with NeXTSTEP roots which help one switch back and forth between the CLI & GUI, I’ve always found a few gaping holes.

Over the last few days, while learning git and playing with github, I’ve grabbed two of the bash scripts I’ve managed to keep ahold of through many a hard drive since 2007: eject & trash. They’ve been polished up a bit and are now part of a collection named tools-osx which I’ll be adding to as I fill empty spaces in my Mac OS X command line toolbox.

Go ahead and download them or grab the source code on github!

post comment

navigation
[ viewing | most recent entries ]