The colrm command is a simple little command that removes columns from standard input before displaying them on the screen (or piping the text into another file). To use, simply cat a file and then pipe it to colrm followed by the start and then stop in $1 and $2. For example, the following would only list the first column of a text file called testfile:

cat testfile | colrm 2

Not providing a second column in the above command caused only the first column to be displayed to the screen. You could pipe all but the second and third columns of a file to another file called testfile2 using the following:

cat testfile | colrm 2 3 > testfile2

One of the most important skills in any language is to know how a basic if then statement works. You set a variable, you say if that variable matches a given pattern (or doesn’t) then do something or else do something different. If/then/else. Other than that, it’s just syntax, and the annoyance of figuring out the operators and syntax. 

So let’s go through the below script (which checks a Mac to see if grayscale is enabled in Universal Access), line-by-line:
  • Line 1: we’re first going to create a variable called grayscale. We’ll fill it with a 0 or 1, the output of a simple “defaults read com.apple.universalaccess grayscale” command
  • If that grayscale variable matches 0 execute whatever is after the then
  • One line just for then followed by the command in the next line (which will optionally allow for an else)
  • Use echo to display the text on the screen that indicates Grayscale is disabled to stdout (which could be redirected if you want to do something after we’re done processing)
  • One line just for the else (optional)
  • The echo to display it’s enabled
  • fi ends the if/then so you can move on to the rest of the script (even if you have nothing after the if/then you’ll need the fi or the script won’t run)
grayscale=`defaults read com.apple.universalaccess grayscale`
if [[ $grayscale = 0 ]]
then
echo "Grayscale is disabled"
else
echo "User doesn't have a token"
fi

In the above if, we used = as an expression. That’s the most common one you’ll likely use, but there are a lot, including the following:
  • [ -a FILE ] True if FILE exists
  • [ -b FILE ] True if FILE exists and is a block-special file
  • [ -c FILE ] True if FILE exists and is a character-special file
  • [ -d FILE ] True if FILE exists and is a directory
  • [ -e FILE ] True if FILE exists
  • [ -f FILE ] True if FILE exists and is a regular file
  • [ -g FILE ] True if FILE exists and its SGID bit is set
  • [ -h FILE ] True if FILE exists and is a symbolic link
  • [ -k FILE ] True if FILE exists and its sticky bit is set
  • [ -p FILE ] True if FILE exists and is a named pipe
  • [ -r FILE ] True if FILE exists and is readable
  • [ -s FILE ] True if FILE exists and has a size greater than zero
  • [ -t FD ] True if file descriptor FD is open and refers to a terminal
  • [ -u FILE ] True if FILE exists and its SUID (set user ID) bit is set
  • [ -w FILE ] True if FILE exists and is writable
  • [ -x FILE ] True if FILE exists and is executable
  • [ -O FILE ] True if FILE exists and is owned by the effective user ID
  • [ -G FILE ] True if FILE exists and is owned by the effective group ID
  • [ -L FILE ] True if FILE exists and is a symbolic link
  • [ -N FILE ] True if FILE exists and has been modified since it was last read
  • [ -S FILE ] True if FILE exists and is a socket
  • [ FILE1 -nt FILE2 ] True if FILE1 has been changed more recently than FILE2, or if FILE1 exists and FILE2 does not
  • [ FILE1 -ot FILE2 ] True if FILE1 is older than FILE2, or is FILE2 exists and FILE1 does not
  • [ FILE1 -ef FILE2 ] True if FILE1 and FILE2 refer to the same device and inode numbers
  • [ -o OPTIONNAME ] True if shell option “OPTIONNAME” is enabled
  • [ -z STRING ] True of the length if “STRING” is zero
  • [ -n STRING ] or [ STRING ] True if the length of “STRING” is non-zero
  • [ STRING1 == STRING2 ] True if the strings are equal. “=” may be used instead of “==” for strict POSIX compliance
  • [ STRING1 != STRING2 ] True if the strings are not equal
  • [ STRING1 < STRING2 ] True if “STRING1” sorts before “STRING2”
  • [ STRING1 > STRING2 ] True if “STRING1” sorts after “STRING2” 
  • [ ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers
Attribution: The above list of expressions was originally borrowed from http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html.

Builtin commands are always kinda’ interesting. At first glance, it’s hard to know which commands are builtins. Luckily, there’s a command that I rarely use, called… command. If you run command with the -V flag it will tell you if the command is a builtin: command -V cd
cd is a shell builtin
If you run a command that isn’t a builtin command -V ls
ls is /bin/ls
Some builtins are in /bin (like echo). But not all builtins are in /bin. Some are in /usr/bin (like cd). Information about how to use builtins is built into the help command rather than standalone man pages. So, if you do help followed by the name of a command, you’ll get information about the command, and sometimes how to use the command: help cd
cd: cd [-L|-P] [dir] Change the current directory to DIR. The variable $HOME is the default DIR. The variable CDPATH defines the search path for the directory containing DIR. Alternative directory names in CDPATH are separated by a colon (:). A null directory name is the same as the current directory, i.e. `.’. If DIR begins with a slash (/), then CDPATH is not used. If the directory is not found, and the shell option `cdable_vars’ is set, then try the word as a variable name. If that variable has a value, then cd to the value of that variable. The -P option says to use the physical directory structure instead of following symbolic links; the -L option forces symbolic links to be followed.
There are also commands not in a path, which can be found using the which command: which dsconfigad
/usr/sbin/dsconfigad

Recently someone asked me about accepting bash inputs. So I decided to take a stab at writing a little about it up. For the initial one we’ll look at accepting text input. Here, we’ll just sandwich a read statement between two echo commands. In the first echo we’ll ask for a name of a variable. Then we’ll read it in with the read command. And in the second echo we’ll write it out. Using the variable involves using the string of the variable (myvariable in this case) with a dollar sign in front of it, as in $myvariable below: echo "Please choose a number: " read myvariable echo "You picked $myvariable" Read also has a number of flags available to it:
  • -a assigns sequential indexes of the array variable
  • -d sets a delimiter to terminate the input
  • -e accepts the line.
  • -n returns after reading a specified number of characters
  • -p prompts without a trailing newline, before attempting to read any input
  • -r doesn’t use a backslash as an escape character
  • -s runs silent, which doesn’t echo text
  • -t: causes read to time out (number of seconds is right after the -t)
  • -u reads input from a file descriptor
Next, we’ll build on that read statement (note the addition of -p) and use a while to force a user to input a y or n and then parse their selection with a basic case statement: while true; do read -p "Do you wish to continue?" yn case $yn in [Yy]* ) echo "Add your action here"; break;; [Nn]* ) exit;; * ) echo "Please answer yes or no.";; esac done Finally, let’s look at positional parameters. Here, you can feed them at the tail end of the script, as words that are separated by spaces after the name of the script. Here, we simply just echo $0, which is the first position (aka – the name of the script you just ran) and $1 and $2 as the next two. #!/bin/bash echo "You Used These" echo '$0 = ' $0 echo '$1 = ' $1 echo '$2 = ' $2 You could also take $3, $4, etc. This is different than writing flags, which requires a bit more scripting. So if you called the script with: /path/to/script/pospar.sh test1 You would see: You Used These $0 = ./pospar.sh $1 = test1 What tips/additions do you have?

So I comment a lot of lines out in my /etc/hosts file. This usually means that I end up with a lot of cruft at the top of my file. And while I write comments into files and scripts here and there, I don’t always want to see them. So I can grep them out by piping the output of the file to grep as follows: cat /etc/hosts | grep -v "^#" You could also do the same, eliminating all lines that start with a “v” instead: cat !$ | grep -v "^v"

When you’re regression testing, you frequently just don’t want any delays for scripts unless you intentionally sleep your scripts. By default Safari has an internal delay that I’d totally forgotten about. So if your GUI scripts (yes, I know, yuck) are taking too long to run, check this out and see if it helps: defaults write com.apple.Safari WebKitInitialTimedLayoutDelay 0 With a script I was recently working on, this made the thing take about an hour less. Might help for your stuffs, might not. If not, to undo: defaults delete com.apple.Safari WebKitInitialTimedLayoutDelay Enjoy.

Dropping network connections can be incredibly frustrating. And finding the source can be a challenge. Over the years, I’ve found a number of troubleshooting methods, but the intermittent drop can be the worse to troubleshoot around. When this happens, I’ve occasionally resorted to scripting around failures, and dumping information into a log file to find the issue. For example, you may find that when a network connection fails, you have a very strong signal somewhere, or that you have a very weak signal on all networks. I’ve found there are three pretty simple commands to test joining/unjoining, and using networks (beyond the standard pings or port scans on hosts). The first is the airport command, along with –disassociate. This just unjoins all networks: sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport --disassociate The second is a quick scan. Here, I’ve grep’d out the network I’m after (aka SSIDofNetwork – a very likely wireless network name), but when looking for environmental issues, you might choose to parse this into a csv and output all networks: sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -s | grep SSIDofNetwork Finally, you can join a network. You might have to escape out special characters in a password and it’s never wise to put a password into a script, etc. But, quick and dirty, this will join that SSIDofNetwork network: sudo networksetup -setairportnetwork en0 "SSIDofNetwork" mysecretpassword Anyway, loop it, invoke it however you invoke it, etc. Hope this helps someone, and if you have other tricks you’ve found helpful, feel free to throw them in the ‘ole comments!

How Users Feel About Intermittent Networking Issues

There are a lot of scripts stored on github. And you can run them directly by curling them into bash. To do so, you’ll need a link to the raw script (using the github page with the URL of the script brings in all the cruft, so you’ll need to find the raw text). To grab that, click on the page with the script and then right-click  on Raw, as seen here: Screen Shot 2016-04-16 at 11.21.48 PM Then, throw out a bash command followed by < and then the URL you just copied into your clipboard in parenthesis:
bash <(curl -Ls https://github.com/krypted/resetsoftwareupdate/raw/master/resetsoftwareupdate.sh)