Raspberry Spi


# Insert an SD card into a Linux PC and;
sudo fdisk -l
#
# Disk /dev/sdb: 3965 MB, 3965190144 bytes
# 49 heads, 48 sectors/track, 3292 cylinders, total 7744512 sectors
# Units = sectors of 1 * 512 = 512 bytes
# Sector size (logical/physical): 512 bytes / 512 bytes
# I/O size (minimum/optimal): 512 bytes / 512 bytes
# Disk identifier: 0x00000000
#
# Device Boot Start End Blocks Id System
# /dev/sdb1 8192 7744511 3868160 b W95 FAT32

sudo umount /dev/sdb1

sudo dd if=archlinux-hf-2013-07-22.img of=/dev/sdb
# 1870+0 records in
# 1870+0 records out
# 1960837120 bytes (2.0 GB) copied, 203.495 s, 9.6 MB/s

sudo fdisk -l
#
# Disk /dev/sdb: 3965 MB, 3965190144 bytes
# 64 heads, 32 sectors/track, 3781 cylinders, total 7744512 sectors
# Units = sectors of 1 * 512 = 512 bytes
# Sector size (logical/physical): 512 bytes / 512 bytes
# I/O size (minimum/optimal): 512 bytes / 512 bytes
# Disk identifier: 0x00057540
#
# Device Boot Start End Blocks Id System
# /dev/sdb1 2048 186367 92160 c W95 FAT32 (LBA)
# /dev/sdb2 186368 3667967 1740800 5 Extended
# /dev/sdb5 188416 3667967 1739776 83 Linux

sudo gparted /dev/sdb
# Expand the sdb2 and sdb5 filesystems to use the whole SD card.

# Move the SD card to the 'pi and connect to a router that has internet access
# and another computer with ssh. The original passwd is 'root'

ssh root@192.168.2.22
# The authenticity of host '192.168.2.22 (192.168.2.22)' can't be established.
# ECDSA key fingerprint is 07:e6:10:f7:75:54:9a:58:af:98:97:e1:a8:f6:17:fb.
# Are you sure you want to continue connecting (yes/no)? yes
# Warning: Permanently added '192.168.2.22' (ECDSA) to the list of known hosts.
# root@192.168.2.22's password:
# X11 forwarding request failed on channel 0
# Last login: Fri Aug 2 00:16:57 2013 from 192.168.2.17
# [root@alarmpi ~]#

passwd
# Zaq12wsX
# Enter new UNIX password:
# Retype new UNIX password:
# passwd: password updated successfully

ping www.google.com
# PING www.google.com (74.125.225.177) 56(84) bytes of data.
# 64 bytes from den03s05-in-f17.1e100.net (74.125.225.177): icmp_seq=1 ttl=49 time=60.6 ms
# 64 bytes from den03s05-in-f17.1e100.net (74.125.225.177): icmp_seq=2 ttl=49 time=59.5 ms
# ^C
# --- www.google.com ping statistics ---
# 2 packets transmitted, 2 received, 0% packet loss, time 1001ms
# rtt min/avg/max/mdev = 59.554/60.077/60.601/0.578 ms

pacman -Syu
# :: Synchronizing package databases...
# core 42.5 KiB 299K/s 00:00 [#################################] 100%
# extra 536.2 KiB 632K/s 00:01 [#################################] 100%
# community 546.9 KiB 753K/s 00:01 [#################################] 100%
# alarm 7.1 KiB 77.2K/s 00:00 [#################################] 100%
# aur 19.1 KiB 407K/s 00:00 [#################################] 100%
# :: Starting full system upgrade...
# resolving dependencies...
# looking for inter-conflicts...
#
# Packages (8): cracklib-2.9.0-1 dhcpcd-6.0.4-1 glib2-2.36.3-3
# libgcrypt-1.5.3-1 libusbx-1.0.16-1 linux-firmware-20130728-1
# netctl-1.2-1 pacman-mirrorlist-20130725-1
#
# Total Download Size: 21.26 MiB
# Total Installed Size: 67.06 MiB
# Net Upgrade Size: 1.43 MiB
#
# :: Proceed with installation? [Y/n] y
# :: Retrieving packages ...
# cracklib-2.9.0-1-armv6h 240.8 KiB 350K/s 00:01 [######################] 100%
# dhcpcd-6.0.4-1-armv6h 88.5 KiB 226K/s 00:00 [######################] 100%
#
# --------- 8< ---------------------------- 8< -------------- # # (7/8) upgrading netctl [#####################################] 100% # (8/8) upgrading pacman-mirrorlist [#####################################] 100% pacman-key --init # gpg: /etc/pacman.d/gnupg/trustdb.gpg: trustdb created # gpg: no ultimately trusted keys found # gpg: Generating pacman keyring master key... # gpg: key 69F70C96 marked as ultimately trusted # gpg: Done # ==> Updating trust database...
# gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
# gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u

reboot

pacman -S netctl
# warning: netctl-1.2-1 is up to date -- reinstalling
# resolving dependencies...
# looking for inter-conflicts...
#
# Packages (1): netctl-1.2-1
#
# Total Installed Size: 0.16 MiB
# Net Upgrade Size: 0.00 MiB
#
# :: Proceed with installation? [Y/n] y
# (1/1) checking keys in keyring [###############################] 100%
# (1/1) checking package integrity [###############################] 100%
# (1/1) loading package files [###############################] 100%
# (1/1) checking for file conflict [###############################] 100%
# (1/1) checking available space [###############################] 100%
# (1/1) reinstalling netctl

cd /etc/netctl/
# This is the directory for setting up networking in Arch

install -m640 examples/wireless-wpa wireless-home
# Install does the same thing as cp, but can alter the mode in the transfer.

vi wireless-home
# Set the ESSID and network password, then save the file.

netctl start wireless-home
# If you just get a prompt back, all is well!

# But, because we're paranoid, lets check.
ifconfig
# eth0: flags=4163 mtu 1500
# inet 10.42.0.43 netmask 255.255.255.0 broadcast 10.42.0.255
# ether b8:27:eb:9b:ed:bd txqueuelen 1000 (Ethernet)
# RX packets 1590 bytes 763883 (745.9 KiB)
# RX errors 0 dropped 0 overruns 0 frame 0
# TX packets 958 bytes 125982 (123.0 KiB)
# TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
#
# lo: flags=73
mtu 16436
# inet 127.0.0.1 netmask 255.0.0.0
# loop txqueuelen 0 (Local Loopback)
# RX packets 0 bytes 0 (0.0 B)
# RX errors 0 dropped 0 overruns 0 frame 0
# TX packets 0 bytes 0 (0.0 B)
# TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
#
# wlan0: flags=4163
mtu 1500
# inet 192.168.2.9 netmask 255.255.255.0 broadcast 192.168.2.255
# ether c8:3a:35:ca:41:a1 txqueuelen 1000 (Ethernet)
# RX packets 12 bytes 2010 (1.9 KiB)
# RX errors 0 dropped 0 overruns 0 frame 0
# TX packets 12 bytes 1768 (1.7 KiB)
# TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
#

netctl enable wireless-home
# This enables the connection after a reboot, kind of important. It also spits out
# the rather cryptic message below;
# ln -s '/etc/systemd/system/netctl@wireless\x2dhome.service' \
# '/etc/systemd/system/multi-user.target.wants/netctl@wireless\x2dhome.service'

reboot
# Verify that wireless comes up

ssh root@192.168.2.9

pacman -Syu
# :: Synchronizing package databases...
# core is up to date
# extra is up to date
# community is up to date
# alarm is up to date
# aur is up to date
# :: Starting full system upgrade...
# there is nothing to do

fdisk /dev/mmcblk0
# Welcome to fdisk (util-linux 2.23.2).
#
# Changes will remain in memory only, until you decide to write them.
# Be careful before using the write command.
#
#
# Command (m for help): p
#
# Disk /dev/mmcblk0: 7913 MB, 7913603072 bytes, 15456256 sectors
# Units = sectors of 1 * 512 = 512 bytes
# Sector size (logical/physical): 512 bytes / 512 bytes
# I/O size (minimum/optimal): 512 bytes / 512 bytes
# Disk label type: dos
# Disk identifier: 0x00057540
#
# Device Boot Start End Blocks Id System
# /dev/mmcblk0p1 2048 186367 92160 c W95 FAT32 (LBA)
# /dev/mmcblk0p2 186368 3667967 1740800 5 Extended
# /dev/mmcblk0p5 188416 3667967 1739776 83 Linux
#
# Command (m for help): n
# Partition type:
# p primary (1 primary, 1 extended, 2 free)
# l logical (numbered from 5)
# Select (default p): p
# Partition number (3,4, default 3): 3
# First sector (3667968-15456255, default 3667968):
# Using default value 3667968
# Last sector, +sectors or +size{K,M,G} (3667968-15456255, default 15456255):
# Using default value 15456255
# Partition 3 of type Linux and of size 5.6 GiB is set
#
# Command (m for help): w
# The partition table has been altered!
#
# Calling ioctl() to re-read partition table.
#
# WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
# The kernel still uses the old table. The new table will be used at
# the next reboot or after you run partprobe(8) or kpartx(8)
# Syncing disks.

reboot
# Just for good measure

ssh root@192.168.2.9
# root@192.168.2.9's password:
# X11 forwarding request failed on channel 0
# Last login: Thu Jan 1 00:00:29 1970 from 192.168.2.17

fdisk -l
# Disk /dev/mmcblk0: 7913 MB, 7913603072 bytes, 15456256 sectors
# Units = sectors of 1 * 512 = 512 bytes
# Sector size (logical/physical): 512 bytes / 512 bytes
# I/O size (minimum/optimal): 512 bytes / 512 bytes
# Disk label type: dos
# Disk identifier: 0x00057540
#
# Device Boot Start End Blocks Id System
# /dev/mmcblk0p1 2048 186367 92160 c W95 FAT32 (LBA)
# /dev/mmcblk0p2 186368 3667967 1740800 5 Extended
# /dev/mmcblk0p3 3667968 15456255 5894144 83 Linux
# /dev/mmcblk0p5 188416 3667967 1739776 83 Linux

mkfs.ext2 /dev/mmcblk0p3
# mke2fs 1.42.8 (20-Jun-2013)
# Filesystem label=
# OS type: Linux
# Block size=4096 (log=2)
# Fragment size=4096 (log=2)
# Stride=0 blocks, Stripe width=0 blocks
# 368640 inodes, 1473536 blocks
# 73676 blocks (5.00%) reserved for the super user
# First data block=0
# Maximum filesystem blocks=1509949440
# 45 block groups
# 32768 blocks per group, 32768 fragments per group
# 8192 inodes per group
# Superblock backups stored on blocks:
# 32768, 98304, 163840, 229376, 294912, 819200, 884736
#
# Allocating group tables: done
# Writing inode tables: done
# Writing superblocks and filesystem accounting information: done

echo "/dev/mmcblk0p3 /home ext2 defaults 0 0" >> /etc/fstab
# Set up a directory to store files.

reboot
# Make sure the mount worked

ssh root@192.168.2.9

timedatectl set-timezone America/New_York

timedatectl status
# Local time: Thu 2013-08-08 02:16:42 EDT
# Universal time: Thu 2013-08-08 06:16:42 UTC
# Timezone: America/New_York (EDT, -0400)
# NTP enabled: yes
# NTP synchronized: no
# RTC in local TZ: no
# DST active: yes
# Last DST change: DST began at
# Sun 2013-03-10 01:59:59 EST
# Sun 2013-03-10 03:00:00 EDT
# Next DST change: DST ends (the clock jumps one hour backwards) at
# Sun 2013-11-03 01:59:59 EDT
# Sun 2013-11-03 01:00:00 EST

pacman -S sudo
# resolving dependencies...
# looking for inter-conflicts...
#
# Packages (1): sudo-1.8.7-1
#
# Total Download Size: 0.62 MiB
# Total Installed Size: 2.82 MiB
#
# :: Proceed with installation? [Y/n] y
# :: Retrieving packages ...
# sudo-1.8.7-1-armv6h 635.9 KiB 604K/s 00:01 [###############] 100%
# (1/1) checking keys in keyring [######################################] 100%
# (1/1) checking package integrity [######################################] 100%
# (1/1) loading package files [######################################] 100%
# (1/1) checking for file conflict [######################################] 100%
# (1/1) checking available space [######################################] 100%
# (1/1) installing sudo [######################################] 100%

visudo
# Append 'pi ALL=(ALL) ALL' to the end of the file.

pacman -S motion
# Time to install the actual software that makes this a web enabled web cam.
# resolving dependencies...
# looking for inter-conflicts...
#
# Packages (62): alsa-lib-1.0.27.2-1 damageproto-1.2.1-2 enca-1.14-1
# ffmpeg-compat-1:0.10.8-4 fixesproto-5.0-2 flac-1.3.0-1 fontconfig-2.10.93-1
# freetype2-2.5.0.1-1 fribidi-0.19.5-1 gsm-1.0.13-7 inputproto-2.3-1
# json-c-0.11-1 kbproto-1.0.6-1 lame-3.99.5-1 libass-0.10.1-1 libasyncns-0.8-4
# libdrm-2.4.46-2 libice-1.0.8-1 libjpeg-turbo-1.3.0-2 libmodplug-0.8.8.4-1
# libogg-1.3.1-1 libpciaccess-0.13.2-1 libpulse-4.0-2 libsm-1.2.1-1
# libsndfile-1.0.25-2 libtheora-1.1.1-3 libva-1.2.1-1 libvdpau-0.7-1
# libvorbis-1.3.3-1 libvpx-1.2.0-1 libx11-1.6.1-1 libxau-1.0.8-1
# libxcb-1.9.1-2 libxdamage-1.1.4-1 libxdmcp-1.1.1-1 libxext-1.3.2-1
# libxfixes-5.0.1-1 libxi-1.7.2-1 libxrender-0.9.8-1 libxtst-1.2.2-1
# libxxf86vm-1.1.3-1 mesa-9.1.6-1 mesa-libgl-9.1.6-1 opencore-amr-0.1.3-1
# openjpeg-1.5.1-1 orc-0.4.17-1 recode-3.6-7 recordproto-1.14.2-1
# renderproto-0.11.1-2 rtmpdump-20121230-2 schroedinger-1.0.11-1
# sdl-1.2.15-3 speex-1.2rc1-3 v4l-utils-0.9.5-2 wayland-1.2.0-1
# x264-20130702-2 xcb-proto-1.8-2 xextproto-7.2.1-1 xf86vidmodeproto-2.3.1-2
# xproto-7.0.24-1 xvidcore-1.3.2-1 motion-3.2.12-10
#
# Total Download Size: 16.99 MiB
# Total Installed Size: 89.23 MiB
#
# :: Proceed with installation? [Y/n] y
# :: Retrieving packages ...
# libjpeg-turbo-1.3.0-2-armv6h 265.3 KiB 241K/s 00:01 [###################] 100%
# v4l-utils-0.9.5-2-armv6h 423.5 KiB 453K/s 00:01 [###################] 100%
# alsa-lib-1.0.27.2-1-armv6h 341.0 KiB 35.7K/s 00:10 [###################] 100%
# gsm-1.0.13-7-armv6h 33.9 KiB 131K/s 00:00 [###################] 100%
# ( 9/62) installing fontconfig [#####################################] 100%
# (61/62) installing ffmpeg-compat [#####################################] 100%
# (62/62) installing motion [#####################################] 100%

useradd -m pi
# Create a user for normal logins

passwd pi
# pi
# Enter new UNIX password:
# Retype new UNIX password:
# passwd: password updated successfully

ssh pi@192.168.2.9
# pi@192.168.2.9's password:

mount
# /dev/mmcblk0p5 on / type ext4 (rw,relatime,data=ordered)
# devtmpfs on /dev type devtmpfs (rw,relatime,size=84784k,nr_inodes=21196,mode=755)
# /dev/mmcblk0p3 on /home type ext2 (rw,relatime)
# The line above is good!
# /dev/mmcblk0p1 on /boot type vfat (rw,shortname=mixed,errors=remount-ro)

mkdir -p /home/pi/motion
# Create a place for our stuff

chmod 750 motion
# Make it a little safer.

systemctl enable motion.service
# ln -s '/usr/lib/systemd/system/motion.service' '/etc/systemd/system/multi-user.target.wants/motion.service'

vi /etc/systemd/system/multi-user.target.wants/motion.service

Meeting-2013-07-27

There will be a meeting Saturday, July 27th, 2013, 10:00am, at the Pleasant Ridge Branch of the Cincinnati Public Library, located at 6233 Montgomery Road, Cincinnati, OH

Google Maps Goodness

I don’t have a topic yet, if there’s something you want to hear about, let me know, but leave out the Spam!
Steve Jones E-Mail

Thank you and hope to see you at the meeting!

Steve Jones

The Meeting Minutes were as follows;
Bill Stowell says:
2013/07/29 at 10:44

My notes on Meeting 7-27-13: Please feel free to comment and add or modify my recollections based on your recollections.

Ideas for the Cincinnati Linux Users Group From meeting 7-27-13

I. Possible interactions with other groups:
a) Python Group in Cincinnati, have members of their group give lectures to Clug, have a joint meeting from time to time
b) University of Cincinnati Linux group, have members of their group give lectures to Clug, have a joint meeting from time to time

interact via special interest groups

Need: Point of contact for discussions
II. Special Interest Groups:
a) Linux Certification Group
1. Comprised of folks who would like to become certified linux administrators, software experts or other.
2. Lay-out certification requirements and materials/study/information needs
3. Develop timelines and milestone events
4. Get the work done—
b) Vulnerability studies group
1. Folks interested in IT security, Current tools for breaching computer security and how they work
2. Choose various available tools to study; obtain source code; ask questions

II. Desired Presentations:
a) New presentation on how to set up MYTH TV
1. Includes general discussion on how the program works and general hardware discussion to include problem areas and insights
2. Includes one “set-up for Dummies”–i.e. This is the specific hardware, software and set-up used and it works.
b) How to set up a web server on Raspberry Pi

c)How to set up and use Amazon cloud/web services

d) Raspberry PI/Arduino Robot how it was done and details

III. Meeting Format:
1) Start meeting with introductions and possible with a linux question of some sort

2) Always have a time to “Solve the Problem” or “Answer the Question”

IV: Other: Community Involvement*

a) Talk with the library we meet in about having a linux install meeting
1. Talk with vendors, refurbishers, schools, businesses about free computers for distribution to the community
b) Talk with churches, schools, etc. about having a linux install time
* The first contacts/viable places to help folks with linux will be the first one we do. In CLUG each member is “the leadership”.

Meeting-2013-06-22

The June meeting will be the CLUG picnic at Rentschler Forest in Butler county!

When: Saturday, June 22nd. 10:30 – Dark
Where: GE Shelter, Rentschler Forest (Follow Signs)
Who: Members (and family) are invited, others may join at the picnic!!!

Now, the important issues, what do we want to eat?
E-Mail me with your dietary delights, but leave out the Spam!
Steve Jones E-Mail

    Bring something to share: Beverages, Side dishes, Desserts!
    We’ll provide meat, flatware, napkins, cups, etc.
    Also, bring outdoor games, group games, maybe water balloons, anything!
    Electricity is NOT available at the site.
    A Motor Vehicle Permit is not required (it’s included with the shelter)
    Membership rates are prorated for new members.
    Since we haven’t collected dues yet, current members are asked to pay up.

Information about the park;

Address of the preserve: 5701 Reigart Rd, Hamilton, OH 45011

The preserve is North of Hamilton, very near the intersection of Route 4 and the Route 4 Bypass.


View Larger Map

Mass mailing from the command line!

This is the little script that sent out the messages for the picnic!

#!/bin/bash
for Each in ` cat CLUGers.txt `
do cat Message.txt | mutt -s "June CLUG meeting" $Each
echo $Each
sleep 10
done

Message.txt is a file in the local directory that contained the body text of the e-mail, CLUGers.txt is a list of email addresses, one per line of the people we wanted to send the e-mail to.

Meeting-2013-05-25

There will be a meeting Saturday, May 25th, 2013, 10:00am, at the Pleasant Ridge Branch of the Cincinnati Public Library, located at 6233 Montgomery Road, Cincinnati, OH

Google Maps Goodness

I don’t have a topic yet, if there’s something you want to hear about, let me know, but leave out the Spam!
Steve Jones E-Mail

Thank you and hope to see you at the meeting!

Steve Jones

Automating Simple Tasks on Linux (Shell Scripts and other Simple Tools) Shells

Monty Stein Mar 24, 2000

There are 2 major groupings of shells in common use. Bourne derived shells evolved from the first Unix shell. Bourne (sh), Korn (ksh) and Bourne Again Shell (bash) are the major variants in use. The other evolutionary branch are the C shells from the early Berkeley Unix systems. csh is the form that most people see. Apparently it is a necessary feature of any shell to have the name form a pun.

Everything below will use Bourne style syntax since it will work on the broadest set of shell programs.

When using a shell it isn’t directly apparent how much power you have at your fingertips. There is a language that shells understand (embodied in shell scripts) that is also available when you are typing in front of one in interactive mode or put into files as scripts.
Globbing
Globbing is the step that is performed on wildcards in filenames to expand them into real filenames. Thus *.log is expanded to a list of all the files in the directory that match the pattern.

*
matches any number of characters
?
matches any one characters
[]
matches a range of characters (like [0-9] for all the numbers)

For example:

echo * # when you don’t have enough of
# a system left to run ls

Input/Output
There are 3 I/O streams that are set up by the shell for any program that it starts. Standard Input (stdin or stream number 0), Standard Output (stdout or #1), and Standard Error (stderr or #2). Normally the program sees it’s input from stdin, sends output to stdout and reports any errors to stderr. These streams can be manipulated before the program sees them by redirecting them. Normal forms of redirection are simply to and from files:

someprog output_file

In this case the input and output are handled by files and any errors would likely be reported to the screen. (Programs, of course, are not limited to use only these streams. However, most shell programming uses support programs of this form.)
Streams can be joined by referencing them by number. Thus:

someprog output.log 2>&1

joins stderr (#2) and stdout (#1) together and put them into output.log. Ordering is critical with this form. The steps read from right to left.

There is one more form of stream and it is called a “Here Document”. Its use is rare. Check the manual page for more information.
Variables
Environment variables are most commonly used to pass some tidbit of information to a program that needs login or machine specific configuration (such as what X display your programs should display to).

To set a variable, the name of the variable is used with an equals sign immediately following (naming convention for environment variables is to use upper case). To access the contents of the variable, use a dollar sign and then the variable name:


/tmp-> VAR=contents
/tmp-> echo $VAR
contents

In places where the name of the variable would touch another alphanumeric character, the variable can be bracketed by curly braces to force the correct behavior:


mv $VAR ${VAR}old

(in this case, the shell would be looking for a variable VARold if the braces were not used)

Variables can be exportable or not. Exported variables are passed to programs that the shell starts (and to any that they start). Unexported variables are restricted to the current shell. Any number of variables can be exported with the export command:

/tmp-> VAR=contents
/tmp-> sh -c 'echo $VAR' # start a subshell as another process

/tmp-> export VAR
/tmp-> sh -c 'echo $VAR' # start a subshell with the exported value
contents

Remember, under the design of the Unix process model, programs spawned by the shell cannot set variables in the parent shell. The way around this is to source a file in the current shell:

/tmp-> . somefile

would run somefile as if it was typed in at that point.

Shorts:

env
will print all the variables that the shell knows about.
export
without any arguments will print all exported variables.
unset
will remove a variable.

Special Variables

$?
return code of the last program
$!
PID of last background process spawned
$$
PID of the current shell, useful for creating temp files
$*
all the arguments to this shell
$0
what this shell was called by
$1 … $9
Arguments to the shell script (more args are there, just call shift to get to them)

Quoting
The shell supports a rich variety of common quoting types (all right, 5).
Double quotes bracket strings and allow variables to be expanded.
Single quotes bracket strings and do not allow any shell string operations inside.
Back quotes will run the contents in a separate shell and return the output IN PLACE.
A backslash will quote a single character.
A pound sign “#” will comment out the rest of the line

/tmp-> VAR=contents
/tmp-> echo "this string has $VAR"
this string has contents
/tmp-> echo "this string has \$VAR"
this string has $VAR
/tmp-> echo 'this string has $VAR'
this string has $VAR
/tmp-> echo `echo $VAR|tr a-z A-Z`
CONTENTS

Job Control
Programs can be run in the background by putting an ampersand “&” at the end of the line. Last backgrounded job process ID is in the “!” variable. wait will wait on all background jobs to finish when called with no arguments, or by PID when it is given as the argument. Wait returns the exit code of the process that it waited on.
Testing and Control Structures
Commands that have completed successfully return a value of 0. This way errors can be identified by a rich set of return codes (thus TRUE is equal to 0 and FALSE is everything else). The last command’s return value is stored in the “?” variable.

The test command sets its return code based on an expression that can return information about a file or compare strings. The test command itself can be accessed by the “[” “]” pair. (For the historically minded: The original Bourne shell didn’t have the square bracket shortcuts and the test program had to be called directly. That is why if you want to get a list of all that test can test you have to run man test.)
A call to test would look something like:

[ -r /tmp/output ]

This would read: If the file /tmp/output is readable, return a TRUE exit status.
Note: When testing the contents of variables, always put them in double quotes. This avoids the problem of:

VAR=""
[ $VAR = junk ]

The shell sees:

[ = junk ]

if $VAR is quoted, the empty string would be visible to the shell.
Check the manual page for test for all the different options that it takes. Note: Some of the test options are platform dependent. Keep them simple for portability sake, use -r (readable) instead of -e (exists) which does not work with HP-UX’s test.
if/then/elif/else/fi

if expression
then
...
elif expression
then
...
else
...
fi

The classical if statement. If the result of expression is TRUE, then execute the then block. The expression can be a call to test or any other program.

if [ ! -d tempdir ] # create a temporary directory
then # if it doesn't already exist
mkdir tempdir
fi

Lazy Evaluation
Lazy evaluation takes advantage of the fact that if A and B must be true in order for something to happen and A is not true, there isn’t any point in evaluating B (the converse for “or” also applies, it just flips the logic). It can shorten simple tests in scripts.
For example: This:

if [ -r somefile ]
then
cat somefile
fi

Will run identically to:

[ -r somefile ] && cat somefile

For “or” the logic inverts. If the first command is not TRUE, execute the second:

[ $RETURNCODE -eq 0 ] || echo "command failed"

case/esac
A case statement allow simplification of lots of nested if/then blocks. It takes the form of:

case value in
pattern1)
...
;;
pattern2)
...
;;
esac

The patterns are matched against the value using the same expansion rules that would be used for filename globbing.
Functions
Functions encompass small, often called portions of a script. From the outside the function looks like another program. From the inside the function everything looks like it is running in a separate shell except that all the variables from the parent script are available to the function for reading and writing.
The return (exit) value is passed with a call to return.

Functions look like:
function somefunc {
echo "hello $1"
return 0
}

And are called like:

somefunc "world"

Looping
for/do/done
For loops iterate over a list of values and execute a block for each entry in the list. They look like

for variable in list
do
...
done

list can be the output from a program or a globbed list. For example:

for filename in *.c
do
cp $filename $filename.backup
done

while/do/done
While loops look and act a lot like for loops, but will loop indefinitely until an expression returns FALSE. It looks like:

while expression
do
...
done

For example:

while [ ! -r "STABLE" ]
do
echo "waiting on STABLE flag"
sleep 60
done

Common Commands
ls
ls will LiSt the contents of a directory. Since most people learn about this command fairly quickly, I’ll focus on the more useful flags:
-S sort by size (GNU only)
-t sort by time last modified
-r reverse sort
-a all files
-d do not enter directory
cut
cut will cut lines of text by column or by delimiter.
-c10-24 would output columns 10 through 24
-d: -f1,3 would output the second and fourth fields delimited by a colon

this:that:the other

returns

this:the other

sed
Stream EDitor. Will run ed style commands on files. The most common way to use it is for search and replace on the fly.

the first line

sed s/first/second/g returns

the second line

tr
character TRanslator. tr can translate one set of characters into another as well as suppress duplicate input characters.

lower case

tr a-z A-Z returns

LOWER CASE

the -s switch will force the suppression of duplicated sequences of characters

this that the other

tr -s ‘ ‘ returns

this that the other

(useful to preprocess a tabular report into something that cut can work on) The -d switch will delete characters (can be very useful with the -c complement switch to return only a given set of characters).

wc -l somefile|tr -cd “0-9” # gives the number of lines
# w/ no other chars

sort
sorts files. The most common way to use this is sort -u to suppress duplicated lines after the sort. A -r will reverse the sort, -n will attempt to convert string based numbers into machine numbers for the sort.
find
Find recursively descends into filesystems and (in the simplest form) prints filenames based on certain criteria.

find . -type f -print

will print the names of all files below the current directory

find . -newer /etc/lastbackup -type d -print

will print the names of all directories that have had files added or deleted since the file /etc/lastbackup was last modified.
xargs
xargs will build up command lines from standard input. When supplied a command to run, it will execute that command with as many arguments built up from it’s input as the OS will allow. -n num will limit the number of args passed to each command invocation

find . -type f -print|xargs grep “your keys”

would search all files below and in the current directory for the string “your keys”
Running Jobs at Certain Times
cron
The crond daemon runs once a minute and runs any jobs scheduled by crontab or at. It normally handles all the recurring jobs that maintain the system. It can also be a huge security hole (there was a notable problem with the vixiecron system in RH5 series). Because of the problems that it use can cause, the cron system has built in to it a way of restricting its use by the allow and deny files that are stored in /etc.
crontab
Each user (that is allowed to) has a crontab file that is read/written with the crontab command. Crontabs are used for jobs that need to be run at regular recurring points in time. The crontab file has this structure:

minute hour month-day month weekday job

So, to fetch mail using a script called /usr/local/bin/getmymail every minute during business hours:

* 7-17 * * 1-5 /usr/local/bin/getmymail

Read as: for every minute between 7am to 5pm from Monday (day 1) to Friday (day 5) run the job /usr/local/bin/getmymail.

Use crontab -l to get the contents of your crontab entries. It is a very good idea to keep a master copy that you can edit and reload.

A possible edit session would be:

crontab -l >mycrontabfile

edit mycrontabfile

crontab mycrontabfile

The scripts that are run will not have any variables but the minimal user environment set. Any scripts that are run should set up any variables that they need (an expanded $PATH variable for example) or assume nothing about the environment they will be running in. Any output generated will be mailed to the user.
at
Runs a job at a specific time. Differs from crontab in that it will run the job only once and that all environment variables are carried through from the shell that called it. The script is to come in via standard input any output will be mailed to the user.

At allows easy setting of the time that the script is to be run:

echo “myscript”|at now + 5 hours

would run myscript 5 hours from now.

echo “someotherscript”|at 5 pm Tuesday

would run someotherscript at the next 5pm on a Tuesday. Be certain to double check the date that at reports when the job is scheduled so that it is what you expected.

At will also run jobs by date:

echo “were you fooled?”|at 5 pm april 1

at -l will list all pending jobs.
atrm (or at -r on some systems) will remove a numbered job.
batch
Close to at now, but holds the job until the load average falls below 0.8 as well as running the job at low priority. Play nice.

BYLAWS OF THE CINCINNATI LINUX USERS GROUP

September 27, 1998
ARTICLE I. NAME
The incorporated organization shall be named the Cincinnati GNU/Linux Users Group, Incorporated, also known as the Cincinnati Linux Users Group, hereinafter known as CLUG.
ARTICLE II. OBJECT
The object of CLUG is to bring together computer users who encourage the study of and use of the GNU/Linux operating system. Education of the members and the general public is a goal of the organization.
ARTICLE III. MEMBERS

Section 1. Membership in the organization shall be open to all who are interested in the GNU/Linux operating system.

Section 2. Classes of membership

Individual, shall pay full membership dues.
Family membership shall include all rights of membership with the understanding that a family membership shall be entitled to one vote, although those having family memberships shall be permitted to make motions and speak in debate, making a dues payment as established for an individual membership.
Student membership, which may result in a reduced dues rate.

Section 3. Dues shall be proposed by the Board of Directors to be approved by the general membership.

The Board of Directors may reduce the dues for a membership on request, determining such reduction in executive session.
Family memberships shall be available to those residing in the same household.

Section 4. The fiscal year begins annually on January 1.

Dues are to be paid on January 1. Dues shall be delinquent if not received by the treasurer by February 1. Members whose dues are delinquent shall be notified of delinquency within two weeks and members whose dues are delinquent after February 28 shall be dropped from membership.
Membership dues shall be prorated on a monthly basis.

ARTICLE IV. BOARD OF DIRECTORS/TRUSTEES

Section 1. The Board of Directors shall serve as trustees of the corporation.

Section 2. The officers shall be a president, vice- president, secretary, and treasurer.

Section 3. There shall be three directors who shall serve with the officers on the Board of Directors.

Section 4. Officers and directors shall be voting members of CLUG; they shall serve one-year terms or until their successors are elected and begin their terms of office. No officer shall serve more than two successive terms in the same position.

Section 5. Election shall take place in November with term of office to begin January 1.

Section 6. A nominating committee of three persons shall be selected by the Board with the chairman of the nominating committee not being a member of the Board. They shall nominate at least one person for each office and directorship and communicate the nominations by mail or electronic means to the membership by October 15. Nominations from the floor shall be accepted.

Section 7. Elections shall be held at the November meeting, with election by ballot unless there is only one nominee for a position when a voice vote may elect.

Section 8. The Board shall meet on call of the president or any two members with notice of at least seven days.

Section 9. The Board shall have general supervision of CLUG between meetings of the general membership and shall be authorized to determine issues which may be deliberated and voted on by electronic means. Quorum of the Board shall be four members.

Section 10. Vacancies in any position of the Board of Directors shall be filled by those remaining on the Board of Directors with the exception of the office of president which shall be filled by the vice-president should that office become vacant.

Section 11. Board of Directors meetings are open to members. The Board may go into executive session for deliberation of sensitive issues.
ARTICLE V. MEETINGS

Section 1. Regular meetings shall be held monthly with the location, time, and date to be determined by the Board of Directors who have the authority to postpone or cancel meetings upon the agreement of four members of the Board with notice by electronic means.

Section 2. The regular meeting in November shall be the annual meeting at which officer and committee reports shall be heard, and election held. Meeting notice of at least fourteen days shall be given to all members by mail or electronic means.

Section 3. Special meetings may be held on the call of four members of the Board, or ten members who request such a meeting with notice of at least seven days by mail or electronic means.

Section 4. The quorum for regular meetings of the membership is ten members.

Section 5. Regular meetings are open to the public.
ARTICLE VI. DUTIES OF OFFICERS

Section 1. Duties of the officers are as follows:

President: The President shall preside at all meetings of the membership and the Board of Directors. The President shall call the regular meetings and special meetings of the organization. The President shall enforce all rules of the organization and perform all duties of the presidents of like organizations. The President is a member ex-officio of all committees except the nominating committee.
Vice-president: The Vice-president shall perform all duties of the President in case of absence or disability of the President.
Secretary: The Secretary shall record minutes of all meetings of the general membership and the meetings of the Board of Directors.
Treasurer: The Treasurer shall assume responsibility for all funds and financial records of the organization. The Treasurer shall issue financial reports at meetings of the general membership and of the Board of Directors.

Section 2. In addition to described duties, officers shall perform other duties customary to the office.
ARTICLE VII. COMMITTEES AND SPECIAL INTEREST GROUPS
The Board of Directors or the general membership gathered in meetings are each empowered to establish committees and special interest groups as needed.
ARTICLE VIII. PARLIAMENTARY AUTHORITY
The rules contained in the current edition of Robert’s Rules of Order Newly Revised shall govern CLUG in all cases to which they are applicable and in which they are not inconsistent with these bylaws and any special rules of order CLUG shall adopt.
ARTICLE IX. AMENDMENTS
These bylaws may be amended at any meeting by a two-thirds vote provided notice of proposed changes, additions, or deletions shall have been submitted in writing thirty days before the meeting. Notice shall be mailed or be sent by email or FAX to all members, at least two weeks before the meeting.

Backing up VirtualBox VMs

This script below is what I use to make backups of running Windows VMs, they are put into hibernation, then the drive is imaged, then the machine is woken back up. There is downtime with this method, but not much and it is easy to schedule as a low use-time service.


#!/bin/bash
##
## Destination of backup files
## Script won't run if directory doesn't exist, and please note that this runs with a normal
## users privileges, so the $BACKUPDEST must be writable by the user running the VM.
BACKUPDEST="/Backup/VMs/${USER}"

## How many days a compressed version will be left on server
DAYS_TO_KEEP_TAR="+7"

## Exempt VMs - Place each VM with a space seperating them
## Example: ( linux winxp win7 ) or
## ( "Ubuntu 8.04" "Windows XP" ) or
## ( None )
## More here: http://www.cyberciti.biz/faq/bash-for-loop-array/
## Run Command to find list of VMS:
## VBoxManage list vms | grep '"' | cut -d'"' -f2 2>/dev/null
EXEMPTION_ARRAY=( None )

## No need to modify below here
IFS=$'\n'
HOST=`hostname`
DATEFILE=`/bin/date +%Y%m%d`
VMLIST=`VBoxManage list vms | grep '"' | cut -d'"' -f2 2>/dev/null`

#################################################################
## Functions

##
## Notify the starting time of backup
##
function startScript {
echo "-----------------------------------------------------"
echo "START - ${VM}"
echo "Host: ${HOST}"
echo "Date: `date`"
echo "-----------------------------------------------------"
echo
}

##
## Create the backup directories if they do not exist
##
function doCheckDirectories {
## Check to see if BACKUPDEST exist
if [ ! -d ${BACKUPDEST} ]; then
echo "BACKUPDEST does not exist!! Exiting Program."
exit 0
fi
## If the archives directory does not exist, create it
if [ ! -d ${BACKUPDEST}/archives ]; then
echo "${BACKUPDEST}/archives directory does not exist, creating . . ."
mkdir "${BACKUPDEST}/archives"
echo
fi
## If the directories directory does not exist, create it
if [ ! -d ${BACKUPDEST}/directories ]; then
echo "${BACKUPDEST}/directories directory does not exist, creating . . ."
mkdir "${BACKUPDEST}/directories"
echo
fi
}

##
## If this VM is in our exempt array, set VM_EXEMPT to skip entirely.
##
function doCheckExempt {
VM_EXEMPT=false
## array, if we get a match, set VM_EXEMPT to true
for check_vm in "${EXEMPTION_ARRAY[@]}"; do
if [ "${check_vm}" = "${VM}" ]; then
echo "${VM} is on the exception list, skipping."
echo
VM_EXEMPT=true
fi
done
}

##
## Suspend VM if its running, skip it if not
##
function suspendVM {
## Check state of VM
VMSTATE=`VBoxManage showvminfo "${VM}" --machinereadable | grep "^\(VMState=\)" | cut -d'"' -f2 2>/dev/null`

echo "${VM} state is currently: ${VMSTATE}"

## If VM is running, suspend it, otherwise, move on
if [ "${VMSTATE}" = "running" ]; then
echo "Suspending ${VM} . . ."
## Stop vm by saving current state (pause|resume|reset|poweroff|savestate)
VBoxManage controlvm ${VM} savestate 2>/dev/null
[ $? ] && echo Success || echo Failure
echo "${VM} Suspended on `date`"
echo
else
echo "${VM} was not running, not suspending - `date`"
echo
fi
}

##
## Backup VM
##
function doBackup {
## Display location of XML file
XMLFILE=`VBoxManage showvminfo "${VM}" --machinereadable \
| grep "^\(CfgFile=\)" \
| cut -d'"' -f2 2>/dev/null`
## Display location of vdi file
## LOCATION=`VBoxManage showvminfo "${VM}" --machinereadable | grep ".vdi" | cut -d'"' -f4 2>/dev/null`
## Display location of vdi or vmdk file
LOCATION=`VBoxManage showvminfo "${VM}" --machinereadable \
| grep -e ".vdi" -e ".vmdk" \
| cut -d'"' -f4 2>/dev/null`

## If the directories directory does not exist, create it
if [ ! -d ${BACKUPDEST}/directories/${VM} ]; then
echo "${BACKUPDEST}/directories/${VM} does not exist, creating . . ."
mkdir "${BACKUPDEST}/directories/${VM}"
echo
fi
## Backup VM (clonehd)
echo "Backing up "${VM}" to ${BACKUPDEST}/directories/${VM}/"
rsync --inplace -a --stats "${XMLFILE}" "${BACKUPDEST}/directories/${VM}/"
[ $? ] && echo Success || echo Failure
rsync --inplace -a --stats "${LOCATION}" "${BACKUPDEST}/directories/${VM}/"
[ $? ] && echo Success || echo Failure
echo
}

##
## Start VM if suspened
##
function doStart {
if [ "${VMSTATE}" = "running" ]; then
echo "Starting ${VM} . . ."
## Resume VMs which were running [--type gui|sdl|vrdp|headless]
VBoxManage startvm ${VM} --type headless
echo "${VM} Resumed on `date`"
[ $? ] && echo Success || echo Failure
else
echo "${VM} was not running, not resuming - `date`"
fi
echo
}

##
## Making a compressed and mobile backup
##
function doTar {
fileName="backup_${VM}-${DATEFILE}.tgz"
echo "taring up ${VM} to ${BACKUPDEST}/archives/${fileName}"
tar -czf "${BACKUPDEST}/archives/${fileName}" "${BACKUPDEST}/directories/${VM}" 2>/dev/null
[ $? ] && echo Success || echo Failure
echo
}

##
## Clean up any tars or logs that are older than DAYS_TO_KEEP_TAR
##
function doCleanTar {
echo "Cleaning up tars older than ${DAYS_TO_KEEP_TAR} day(s) old"
find "${BACKUPDEST}/archives" -name "backup_${VM}*.tgz" -mtime ${DAYS_TO_KEEP_TAR} -exec rm -vf {} \;
[ $? ] && echo Success || echo Failure
echo "Cleaning up logs older than ${DAYS_TO_KEEP_TAR} day(s) old"
find "${BACKUPDEST}/" -name "*-log" -mtime ${DAYS_TO_KEEP_TAR} -exec rm -vf {} \;
[ $? ] && echo Success || echo Failure
}

##
## Notify the finishing time of backup
##
function finishScript {
echo
echo "-----------------------------------------------------"
echo "FINISH - ${VM}"
echo "Host: ${HOST}"
echo "Date: `date`"
echo "-----------------------------------------------------"
}

#################################################################
## Script

## Make sure we have the appropriate directories for backups
doCheckDirectories
## Start loop
for VM in ${VMLIST}; do
sleep 1
## Check exempt list
doCheckExempt
if [ "$VM_EXEMPT" = "false" ]; then
startScript
## Suspend VM
suspendVM
sleep 3
## Do Backup
doBackup
## Start if suspended
doStart
## Compressing backup
doTar
sleep 3
## Clean old backups
doCleanTar
sleep 3
finishScript
fi
## Reset exemption
shift
done >> ${BACKUPDEST}/${DATEFILE}-log
################################################################

Rsync to Fat32 drives

I regularly provide one of my clients with a backup of his data in the form of an external hard drive. Since his server runs CentOS Linux and his computer is a Windows machine, I need to provide a drive formatted Fat32 so he can plug it into his computer and access the data without problem.

# mount -t vfat /dev/sdc1 /mnt/usb -o shortname=mixed -o utf8

The “shortname=mixed” keeps the case preserved, as otherwise vfat will convert any filename that’s 8 characters or less to lower case (default behavior is “shortname=lowercase”) and cause problems for rsync. UTF8 is what Windows uses when mounting filesystems, so we specify that to ensure that we’re mounting it the same way (default is to mount iso-8859-1, even though the underlying vfat filesystem will store filenames in UTF8 format).

My normal mirror command, “rsync -az /home /mnt/usb“, doesn’t work because -a is a shortcut for the following options:

-a, –archive archive mode; same as -rlptgoD (no -H)
-r, –recursive recurse into directories
-l, –links copy symlinks as symlinks
-p, –perms preserve permissions
-t, –times preserve times
-o, –owner preserve owner (super-user only)
-D same as –devices –specials
-g, –group preserve group

Using -o will cause errors, as rsync will copy the file and then chown (change owner) the file. Fat32 doesn’t support Unix owership or permissions, so rsycn will error on every file that is copied. Ditto for -p and -g. Symlinks aren’t supported either, and we don’t want -L to copy the destination file of the symlink (that will produce multiple copies of a file/directory, not desirable in this particular instance). The -D option is irrelevant because we are only copying website data, so we don’t need special devices (/dev/*).

That leaves -r (recursive), -t (preserve times) for our vfat options. There’s no need to use compression (-z) since we’re not syncing across the network.

So the best command to copy form ext3 to Fat32 drive is something like this:

rsync -rtv /home /mnt/usb

I like using -v for verbosity, unless I’m running this within a shell script.

A good reference for further reading on Fat32 with Linux:
http://www.osnews.com/story/9681/The_vfat_file_system_and_Linux/