[guide] Terminal tips and tricks


Recommended Posts

Here are some terminal shell tips I've compiled together. Most of the information came from googling around and fooling around. I'm in the process of better understanding Applescript, so hopefully more content is to come.

This is a short guide on simplifying the Terminal to Mac OS GUI interface. I personally find that I can work faster using a well refined shell environment then i can by clicking around in the Finder. I will, however, admit that using a shell isn't for everyone.

I found while initially using the Darwin shell that there was a strong disconnection between that shell environment and the graphical world that is the Mac OS. I could identify the connection between where things were from a finder window to a Unix path in Darwin. I could use the Unix commands I knew from using various Unix versions and Linux after all these years (ls, rm, cat, echo.) Something else I could do "right out of the box" was drag and drop a file from a Finder window into the terminal and have it copy the full unix path of the file wherever my cursor was. Cool.

With a little Applescript and Bash Shell Scripting, I was able to piece together a very usable Shell interface and can work quickly in it to get jobs done.

Introductory Notes

You can assume that any line in a code block that starts with a "$ " is a shell prompt, and characters after are typed directly into the shell. Example:

$ echo this is a test

Explicitly means: i typed "echo this is a test" into the Terminal at a shell prompt.

I am using Bash as my default shell, and therefore my shell scripts only run in that shell environment. You can find out what shell you are using by typing:

$ echo $SHELL

If you are not currently using Bash and want to switch, goto Terminal->Preferences and select "Execute this command (specify complete path):" and type the path "/bin/bash".

You may also want to change your default window settings to look prettier. "Courier New 18pt" with Anti-aliasing is what I use for my font. The default looks like crap. A nice background and transparency effect can make it look a lot more like a part of the Mac OS system.

This guide assumes you are familiar with working in a shell environment and are comfortable with shell commands. It is beyond the scope of this guide to teach you how to open and edit a file in the shell.

open -a TextEdit /path/to/file

This might get you somewhere if you are loss, but if that be the case you should probably read up on a general howto use a Unix shell. There are about a million out there.

I prefer Vim/gVim over TextEdit, but you may or may not have it installed or are interested in trying it.

~/bin

I have my own bin folder in my home folder that I put all my scripts and executables in. Avoid using the system bin (/bin) for your own creations.

.profile

.profile is a Bash file that is in your home directory (/Users/$USER/ or simply ~/) and is run whenever Terminal is opened. Here is my final .profile:

#Mac OS Programs aliases
alias gvim="open -a gvim"
alias photoshop="open -a \"adobe photoshop cs\""
alias illustrator="open -a \"illustrator cs\""
alias safari="open -a safari"
alias firefox="open -a firefox"
alias sedit="open -a \"/Applications/AppleScript/Script Editor.app/\""
alias preview="open -a preview"
alias word="open -a \"Microsoft Word\""
#interesting list modes
alias list="ls -CF"
alias lam="ls -al | more"

#Sometimes it is better to move folders and files into the trash
#rather then "rm"ing them.
alias trash="osascript ~/bin/trash.scpt"

#iTunes involves some cleverness for speed reasons
function itunes () 
{
	osascript ~/bin/itunes.scpt $* &
}

#add my personal bin folder to the path
export PATH=$PATH:~/bin

#set my super cool shell prompt
PS1="\n\[\033[0;37m\].: \[\033[1;33m\]\w\[\033[0;37m\] :: [\[\033[0;37m\]\t \@\[\033[0;37m\]] \n\h [\!]: \[\033[1;37m\]"

The aliases leverage the long strings that you use over and over again, such as "open -a..." which opens a particular application that you have in either /Applications or ~/Applications. Sometimes you have to give it a very specific path to the .app file, other times you can just give the name. It takes some fooling around, and some investigation work on your part to get right.

Now I can type:

$ photoshop neat_graphic.jpg

and Adobe Photoshop will open with the neat_graphic.jpg. If it is already open, then it is brought to the front.

AppleScript

Applescript can be executed from the shell using the "osascript" utility. You should use "Script Editor" and compile your code, but it should be able to read any text file and execute the code within.

Here is my ~/bin/trash.scpt

on run argv
	set file_path to item 1 in argv
	set theMacOSXPath to (POSIX file file_path) as string
	tell application "Finder" to delete theMacOSXPath as alias
end run

I wrote it because rm -R /folder, scares me :D. And I'm already using the trash so much! If you plan to pass parameters from the shell to the script, you must wrap your code up in a "on run argv" statement. The Unix file path might also need to be converted to a Mac OS X path and vise versa depending on what you are doing. More on that here.

Here is my ~/bin/itunes.scpt

on run argv
	tell application "iTunes"
		if not (exists playlist "Script Playlist") then
			make new playlist with properties {name:"Script Playlist"}
		else
			delete every track of playlist "Script Playlist"
			repeat while (number of tracks of playlist "Script Playlist") > 0
				delay 0.1 -- wait for the library to clear out
			end repeat
		end if
		set play_string to ""
		repeat with ThisItem in argv
			set play_string to play_string & " " & ThisItem
		end repeat
		set trax to (search library playlist 1 for play_string)
		set p to false
		--duplicate item 1 of trax to playlist "Script Playlist"

		repeat with t in trax
			try
				duplicate t to playlist "Script Playlist"
				if not p then
					repeat while (number of tracks of playlist "Script Playlist") = 0
						delay 0.1 -- wait for track to be added
					end repeat
					play track 1 of playlist "Script Playlist"
					set p to true
				end if
			end try
		end repeat
	end tell
end run

Source

This, along with the function itunes() declared in my .profile allow me to type:

$ itunes royksopp

at the shell prompt, and have itunes look up "royksopp" and plays the first one. The function is declared so that the "&" operator can be used and my shell prompt is returned immediately, instead of waiting for iTunes to finish loading all the songs. If there were 100's of songs in the query, it could take awhile. I'm still working on an implementation that detects if the input argument is an actual file, and tells iTunes to play that file. But something is wrong with the file detection argument (-e) of the "test" (or [) program for bash (i think). This is what I came up with in a shell script:

#!/bin/bash
if [ -e $1 ]; then
	open -a "itunes" $1
else
	osascript ~/bin/itunes.scpt $1 &
fi

Haven't had much luck with it.

be a tab ninja :shiftyninja: and other misc shell tips

What I like about the shell is the auto-complete with the "tab" key. Try it out to see what I'm talking about. That is what I think makes it faster to navigate around in the shell as oppose to a Finder window.

"touch" is useful for creating a specific file. Sometimes applescript or the open command will throw back "file not found" or something similar if you are trying to open a file that doesn't exist yet in a program. Try:

$ touch mynewfile.doc
$ word mynewfile.doc

if you have any problems.

Well..thats a start, anyway. Hopefully it was helpful.

Comments? Questions?

-Shadrack

Link to comment
Share on other sites

Here is an alarm and sleep script, I modified from here.

wakeup.sh

#!/bin/sh

# This script plays music and speaks to you to wake you up
# after a specified number of hours & minutes

# Functions
#--------------------------------

music_app="iTunes"

speak_message()
{
  message="$*"
  echo "say \"$message\"" | /usr/bin/osascript
}

speak_time()
{
  hour=`date "+%H"`
  time=`date "+%I %M"`
  if [ $hour -le 11 ]; then
	message="The time is now $time A-M"
  else
	message="The time is now $time P-M"
  fi
  speak_message $message
}

start_music()
{
#  artist="$*"
  #echo "tell application \"$music_app\" to play (some track of playlist \"Library\" whose artist is \"$artist\")" | /usr/bin/osascript
  echo "tell application \"$music_app\" to play (some track of playlist \"Alarm\")" | /usr/bin/osascript
}

pause_music()
{
  echo "tell application \"$music_app\" to pause" | /usr/bin/osascript
}

resume_music()
{
  echo "tell application \"$music_app\" to play" | /usr/bin/osascript
}

fade_in_volume()
{
	#
	sound_initial_volume=0
	sound_increment_amount=2
	sound_increment_rate=.1

	the_volume=$sound_initial_volume

	echo "tell application \"itunes\" to set the sound volume to $sound_initial_volume" | /usr/bin/osascript

	while [ $the_volume -lt 100 ]
	do
		sleep $sound_increment_rate
		the_volume=`expr $the_volume + $sound_increment_amount`
		echo "tell application \"iTunes\" to set the sound volume to $the_volume" | /usr/bin/osascript
	done
}
fade_in_volume_quickly()
{
	sound_initial_volume=35
	sound_increment_amount=5
	sound_increment_rate=.01

	the_volume=$sound_initial_volume

	twice_initial_volume=`expr $sound_initial_volume \* 2`
	echo "tell application \"itunes\" to set the sound volume to $sound_initial_volume" | /usr/bin/osascript
	while [ $the_volume -lt 100 ]
	do
		sleep $sound_increment_rate
		the_volume=`expr $the_volume + $sound_increment_amount`
		echo "tell application \"iTunes\" to set the sound volume to $the_volume" | /usr/bin/osascript
	done
}



# Command-line arguments
#--------------------------------

if [ $# -lt 1 ]; then
  echo "Usage: $0 hours [minutes]"
  exit
fi

hours=$1
minutes=0
if [ $# -gt 1 ]; then
  minutes=$2
fi

ack_msg="I will wake you up in $hours hours and $minutes minutes"
speak_time
speak_message $ack_msg

# Sleep until it's time to wakeup
#--------------------------------

delay_seconds=`expr $hours \* 3600 + $minutes \* 60`
sleep $delay_seconds

name=$USER
message0="Time to get your lazy ass out of bed and get to work!"
message1="Wake up!"
message2="You are going to be late."
message4="Think about breakfast!"
message3="Time to Wake Up, Knickerbocker."



announce_delay=400
run_for=7200
has_run_for=0

# Deliver wake-up message
#--------------------------------
fade_in_volume &
start_music $artist1

while [ $has_run_for -lt $run_for ]
do
	sleep $announce_delay
	has_run_for=`expr $has_run_for + $announce_delay`
	fade_in_volume_quickly &
	sleep .5
	speak_time
	random_message=message`expr $RANDOM % 4`
	eval random_message=\$$random_message
	speak_message $random_message
done
pause_music

My modification includes random messages, and cool fade-in and fade-out. Usage "wakeup.sh hours mins". Example:

$ ./wakeup.sh 0 30

To wake up in 30 minuets. Also be sure to have a Playlist named "Alarm" or change the script to a playlist that better suits you. I was using "Most Recently Played" smartlist, but found the techno songs annoying in the morning. Be sure to also "chmod 755 wakeup.sh"

Slightly modified version creates a sleep script:

sleep.sh

#!/bin/sh

# Functions
#--------------------------------

music_app="iTunes"

speak_message()
{
  message="$*"
  echo "say \"$message\"" | /usr/bin/osascript
}

speak_time()
{
  hour=`date "+%H"`
  time=`date "+%I %M"`
  if [ $hour -le 11 ]; then
	message="The time is now $time A-M"
  else
	message="The time is now $time P-M"
  fi
  speak_message $message
}

start_music()
{
#  artist="$*"
  #echo "tell application \"$music_app\" to play (some track of playlist \"Library\" whose artist is \"$artist\")" | /usr/bin/osascript
  echo "tell application \"$music_app\" to play (some track of playlist \"Recently Played\")" | /usr/bin/osascript
}

pause_music()
{
  echo "tell application \"$music_app\" to pause" | /usr/bin/osascript
}

# Command-line arguments
#--------------------------------

if [ $# -lt 1 ]; then
  echo "Usage: $0 hours [minutes]"
  exit
fi

hours=$1
minutes=0
if [ $# -gt 1 ]; then
  minutes=$2
fi

ack_msg="I will stop playing music in $hours hours and $minutes minutes"
speak_time
speak_message $ack_msg

# Sleep until it's time to wakeup
#--------------------------------

delay_seconds=`expr $hours \* 3600 + $minutes \* 60`
sleep $delay_seconds

pause_music

Usage should be fairly obvious. You could be proactively lazy and create aliases for the commands in your .profile. You could also add wakeup.sh to your /etc/crontab file to schedule an alarm monday-friday or whatever.

$ sudo vim /etc/crontab

to open crontab (you need root privileges). Does anyone know how to open an .app type application with "root" privileges? sudo open -a .... doesn't work like expected.

crontab:

00			  23	  *	   *	   0-4	 shadrack	 /Users/shadrack/bin/wakeup.sh 8 15

This executes the script at 11 PM sunday-through thursday to wake me up at 7:15am monday-friday. You can learn more about cron tab by typing:

$ man crontab

or googling. There is probably also a Mac OS applet that handles setting up cron jobs.

-shad

Link to comment
Share on other sites

There was an iTunes status script available on MacOSX Hints;

#!/bin/sh
#
####################################
# iTunes Command Line Control v1.0
# written by David Schlosnagle
# created 2001.11.08
####################################

showHelp () {
	echo "-----------------------------";
	echo "iTunes Command Line Interface";
	echo "-----------------------------";
	echo "Usage: `basename $0` <option>";
	echo;
	echo "Options:";
	echo " status   = Shows iTunes' status, current artist and track.";
	echo " play	 = Start playing iTunes.";
	echo " pause	= Pause iTunes.";
	echo " next	 = Go to the next track.";
	echo " prev	 = Go to the previous track.";
	echo " mute	 = Mute iTunes' volume.";
	echo " unmute   = Unmute iTunes' volume.";
	echo " vol up   = Increase iTunes' volume by 10%";
	echo " vol down = Increase iTunes' volume by 10%";
	echo " vol #	= Set iTunes' volume to # [0-100]";
	echo " stop	 = Stop iTunes.";
	echo " quit	 = Quit iTunes.";
}

if [ $# = 0 ]; then
	showHelp;
fi

while [ $# -gt 0 ]; do
	arg=$1;
	case $arg in
		"status" ) state=`osascript -e 'tell application "iTunes" to player state as string'`;
			echo "iTunes is currently $state.";
			if [ $state = "playing" ]; then
				artist=`osascript -e 'tell application "iTunes" to artist of current track as string'`;
				track=`osascript -e 'tell application "iTunes" to name of current track as string'`;
				echo "Current track $artist:  $track";
			fi
			break;;

		"play"	) echo "Playing iTunes.";
			osascript -e 'tell application "iTunes" to play';
			break;;

		"pause"	) echo "Pausing iTunes.";
			osascript -e 'tell application "iTunes" to pause';
			break;;

		"next"	) echo "Going to next track.";
			osascript -e 'tell application "iTunes" to next track';
			break;;

		"prev"	) echo "Going to previous track.";
			osascript -e 'tell application "iTunes" to previous track';
			break;;

		"mute"	) echo "Muting iTunes volume level.";
			osascript -e 'tell application "iTunes" to set mute to true';
			break;;

		"unmute" ) echo "Unmuting iTunes volume level.";
			osascript -e 'tell application "iTunes" to set mute to false';
			break;;

		"vol"	) echo "Changing iTunes volume level.";
			vol=`osascript -e 'tell application "iTunes" to sound volume as integer'`;
			if [ $2 = "up" ]; then
				newvol=$(( vol+10 ));
			fi

			if [ $2 = "down" ]; then
				newvol=$(( vol-10 ));
			fi

			if [ $2 -gt 0 ]; then
				newvol=$2;
			fi
			osascript -e "tell application \"iTunes\" to set sound volume to $newvol";
			break;;

		"stop"	) echo "Stopping iTunes.";
			osascript -e 'tell application "iTunes" to stop';
			break;;

		"quit"	) echo "Quitting iTunes.";
			osascript -e 'tell application "iTunes" to quit';
			exit 1;;

		"help" | * ) echo "help:";
			showHelp;
			break;;
	esac
done

I added the ability to execute your script from it :cool:, here we go;

#!/bin/sh
#
####################################
# iTunes Command Line Control v1.0
# written by David Schlosnagle
# created 2001.11.08
####################################

showHelp () {
	echo "-----------------------------";
	echo "iTunes Command Line Interface";
	echo "-----------------------------";
	echo "Usage: `basename $0` <option>";
	echo;
	echo "Options:";
	echo " status   = Shows iTunes' status, current artist and track.";
	echo " play	 = Start playing iTunes.";
	echo " pause	= Pause iTunes.";
	echo " next	 = Go to the next track.";
	echo " prev	 = Go to the previous track.";
	echo " band	 = Play the first song with this name.";
	echo " mute	 = Mute iTunes' volume.";
	echo " unmute   = Unmute iTunes' volume.";
	echo " vol up   = Increase iTunes' volume by 10%";
	echo " vol down = Increase iTunes' volume by 10%";
	echo " vol #	= Set iTunes' volume to # [0-100]";
	echo " stop	 = Stop iTunes.";
	echo " quit	 = Quit iTunes.";
}

if [ $# = 0 ]; then
	showHelp;
fi

while [ $# -gt 0 ]; do
	arg=$1;
	case $arg in
		"status" ) state=`osascript -e 'tell application "iTunes" to player state as string'`;
			echo "iTunes is currently $state.";
			if [ $state = "playing" ]; then
				artist=`osascript -e 'tell application "iTunes" to artist of current track as string'`;
				track=`osascript -e 'tell application "iTunes" to name of current track as string'`;
				echo "Current track $artist:  $track";
			fi
			break;;

		"play"	) echo "Playing iTunes.";
			osascript -e 'tell application "iTunes" to play';
			break;;

		"pause"	) echo "Pausing iTunes.";
			osascript -e 'tell application "iTunes" to pause';
			break;;

		"next"	) echo "Going to next track.";
			osascript -e 'tell application "iTunes" to next track';
			break;;

		"prev"	) echo "Going to previous track.";
			osascript -e 'tell application "iTunes" to previous track';
			break;;
		"band"	) echo "Playing band $2.";
			osascript ~/bin/band.scpt $2;
			break;;

		"mute"	) echo "Muting iTunes volume level.";
			osascript -e 'tell application "iTunes" to set mute to true';
			break;;

		"unmute" ) echo "Unmuting iTunes volume level.";
			osascript -e 'tell application "iTunes" to set mute to false';
			break;;

		"vol"	) echo "Changing iTunes volume level.";
			vol=`osascript -e 'tell application "iTunes" to sound volume as integer'`;
			if [ $2 = "up" ]; then
				newvol=$(( vol+10 ));
			fi

			if [ $2 = "down" ]; then
				newvol=$(( vol-10 ));
			fi

			if [ $2 -gt 0 ]; then
				newvol=$2;
			fi
			osascript -e "tell application \"iTunes\" to set sound volume to $newvol";
			break;;

		"stop"	) echo "Stopping iTunes.";
			osascript -e 'tell application "iTunes" to stop';
			break;;

		"quit"	) echo "Quitting iTunes.";
			osascript -e 'tell application "iTunes" to quit';
			exit 1;;

		"help" | * ) echo "help:";
			showHelp;
			break;;
	esac
done

This new file assumes your iTunes script is "~/bin/band.scpt"

Link to comment
Share on other sites

thats a long one. I have most of my iTunes controls globally hotkeyed so I dunno.

Although i was wondering if there was a way to get output from an AppleScript command to my shell script and you have a good example in there.

thx.

Link to comment
Share on other sites

Now I can type:

$ photoshop neat_graphic.jpg

and Adobe Photoshop will open with the neat_graphic.jpg. If it is already open, then it is brought to the front.

why not just click the PS icon on the doc...?

Link to comment
Share on other sites

why not just click the PS icon on the doc...?

Edit: I think I can answer your question more quickly. If I just want Photoshop open, yeah clicking on the dock or looking it up through spotlight is a hell of a lot faster then opening a terminal. If I need to open a file, in most circumstance I can get to that file faster through the Terminal then Finder. A few keystrokes combined with <tab> and I'm there.

------original post-----

I do that when it is more convenient to do. But whenever I'm working on, say a web page, I find myself more comfortable jumping around directories in a shell environment then I do in any GUI. I know all the commands to do stuff like set permissions and open a file in a particular application.

Like I said, the shell isn't for everyone. But I would argue that someone who is proficient at using a shell could do a list of normally "Finder" intensive tasks (creating directories, compressing files, opening this file in that program, creating a new file with this extension, make this file executable by anyone and this other file read only...make these files with this particular regular expression pattern have these permissions...etc..etc...etc). You also game the benefits of being more capable of remote controlling your Mac from across the internet through SSH, which will be faster and more convenient then a VNC session. Also, you can write shell scripts that automate processes a lot easier then you can write UI scripts to automate mouse movement or something.

But sitting down and learning such things is probably not worth your time. It all depends on what you do with your computer I suppose. Not for everyone, but I thought I would share what I've found works well for me coming from a Linux environment.

Edit: Just for clarification: I love Finder an think it is a wonderful tool. I use it all the time, and I'm not all die hard shell or nothing. Depends on what I am doing.

Edited by Shadrack
Link to comment
Share on other sites

Edit: I think I can answer your question more quickly. If I just want Photoshop open, yeah clicking on the dock or looking it up through spotlight is a hell of a lot faster then opening a terminal. If I need to open a file, in most circumstance I can get to that file faster through the Terminal then Finder. A few keystrokes combined with <tab> and I'm there.

------original post-----

I do that when it is more convenient to do. But whenever I'm working on, say a web page, I find myself more comfortable jumping around directories in a shell environment then I do in any GUI. I know all the commands to do stuff like set permissions and open a file in a particular application.

Like I said, the shell isn't for everyone. But I would argue that someone who is proficient at using a shell could do a list of normally "Finder" intensive tasks (creating directories, compressing files, opening this file in that program, creating a new file with this extension, make this file executable by anyone and this other file read only...make these files with this particular regular expression pattern have these permissions...etc..etc...etc). You also game the benefits of being more capable of remote controlling your Mac from across the internet through SSH, which will be faster and more convenient then a VNC session. Also, you can write shell scripts that automate processes a lot easier then you can write UI scripts to automate mouse movement or something.

But sitting down and learning such things is probably not worth your time. It all depends on what you do with your computer I suppose. Not for everyone, but I thought I would share what I've found works well for me coming from a Linux environment.

Edit: Just for clarification: I love Finder an think it is a wonderful tool. I use it all the time, and I'm not all die hard shell or nothing. Depends on what I am doing.

That's what spotlight is for. Command-space, <type name of file>, click file. Assuming it opens by default in photoshop of course.

Link to comment
Share on other sites

That's what spotlight is for. Command-space, <type name of file>, click file. Assuming it opens by default in photoshop of course.

doesn't work very well for all the files named "background.png" i have in various folders :p.

Link to comment
Share on other sites

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.