Find the End of the Week with PHP

Just had a need to to represent the end of the current week in PHP. A quick Google search turned up a bunch of clumsy ways. The most common was to run the current date and day of the week through some math to get the date of Next Friday.

Fortunately thinking of those last two words reminded me of an easier way, and one that I use in BASH occasionally. PHP's strtotime function takes a similar language that GNU Date does. So to find out the date of next friday, just use this line of code:

$week_ending = date('Y-m-d', strtotime( 'Next Friday'));

You can also use "This Friday" which will return today's date on a Friday instead of a week from today.

Sed – Stream Editor – Cheat Sheet – good coders code, great reuse

post-icon-sed.jpgSed - Stream Editor - Cheat Sheet - good coders code, great reuse

I present to you my cheat sheet of sed, the Superman of stream editing! It has come handy 101 times for me because sed is not what I use daily and after some time of not using the sed commands tend to fade away from my mind and I have to review them quickly. This cheat sheet is ideal for that!

Very cool cheat sheet for all the sed aficionados in the house.

BASH: Split a string without ‘cut’ or ‘awk’

For a little test script I'm writing I needed to split a line on a ';' but preservere the "s and 's, something that echo doesn't like to do. Digging deeper into the bash docs I see that there are some handy string handling functions.

#!/bin/bash
line='this "is" a command;this "is" a pattern'
COMMAND=${line%;*}
PATTERN=${line#*;}
echo $COMMAND
echo $PATTERN

And the output would be:

this "is" a command
this "is" a pattern

BASH: Convert Unix Timestamp to a Date

I've been asked this a number of times and always have to look it up, so here are 3 ways to convert a unix timestamp (seconds since Jan 1, 1970 GMT) to a real looking date.
Perl method 1: use the ctime module:

perl -e "require 'ctime.pl'; print &ctime($EPOCH);"

Perl method 2: use the scalar and localtime functions:

perl -e "print scalar(localtime($EPOCH))"

Awk has a wrapper for the standard C strftime function:

echo $EPOCH|awk '{print strftime("%c",$1)}'

Here's a sample script that uses all methods.

!#/bin/bash
EPOCH=1000000000
DATE=$(perl -e "require 'ctime.pl'; print &ctime($EPOCH);")
echo $DATE
DATE=$(perl -e "print scalar(localtime($EPOCH))")
echo $DATE
DATE=$(echo $EPOCH|awk '{print strftime("%c",$1)}')
echo $DATE

[update: Thanks to S. Maynard for reminding me of the proper use of quotes and how to avoid using the pipe...]
DATE=$(awk "BEGIN { print strftime(\"%c\",$EPOCH) }")

[UPDATE]

A reader found another way listed below. This doesn't seem to be as portable (The mac ignores the --date and -d is an illegal option).
# date --date='1970-01-01 1000000000 sec GMT'
Sat Sep 8 20:46:40 CDT 2001

[UPDATE]
# date -d @1000000042
Sun Sep  9 01:47:22 GMT 2001

But this only works on newer versions of date.  It fails on my FC2 server and my Debian Sarge machine, but works fine on Ubuntu Feisty and Debian Etch.

functions and error handling

.!.

Last time I tweaked the parser, tonight I'm going to move some of the code into functions. Many people think of functions as a way to reuse the same code, but they can also be used to seperate logic into bite sized chucks. This can often lead to code that's easier to read, and makes modifying things later easeir, both for you, and anyone else who wants to enhance the script.

#!/bin/bash shopt -s nocaseglob BASEDIR="/mnt/usb0/mp3/podCast" FEEDS="${BASEDIR}/feeds.lst" CACHEDIR="${BASEDIR}/cache" LOGFILE="${BASEDIR}/log"

Not much change here except I've added two config variables, CACHEDIR, and LOGFILE. The former will be used for caching the feed XML to help minimize network transfers, both for us and more importantly the feed provider. The later is for reporting errors, some of the functions will output lists of things to be piped into a loop, we can't just echo the errors.

Continue reading

updated parser

.!.

In my last post I was using if and else to look for each tag, and act on it. Tonight I'm going to convert that ugly mess to a case statement. It's easier to read, and doesn't have the hackish feel of if then, else.

I also learned a new trick that will help in parsing tags if the author mixes case. We'll add a 'shopt -s nocaseglob' to the top of the shell script. This causes wildcard and regexp matches to be case insensitive. It does not, however, change the behaviour of commands like sed and grep. I've already seen a couple feeds there the tags were all upper case, and was worried about having to write some ugly regexp to match the tags.

#!/bin/bash shopt -s nocaseglob

Continue reading

process substitution in bash

.!.

The internets are slow tonight, and I'm tired, so I'll just leave you with something quick. Tommorrow I'll pick back up on the podcast script.

Let's look at this short script:


#!/bin/bash
LIST=""
ls | while read FILE ; do
   LIST="${FILE} ${LIST}"
done
echo $LIST

You may be suprised to find that LIST is empty after all that looping. This problem always mystified me until I learned about subshells. The pipe creates another shell, a subshell, where the loop executes. When the pipe ends, so does the subshell and all of it's variables.

Fortunately there is a simple way around this. We need to execute the loop in the current shell, and redirect the command back into the loop from a subshell.


#!/bin/bash
LIST=""
while read FILE ; do
   LIST="${FILE} ${LIST}"
done < <(ls)
echo $LIST

<(ls) creates an un-named pipe from the subshell into this shell. We can now redirect that pipe into the loop with another <.

If that got too confusing, try reading the Process Substitution chapter in the Advanced Bash-Scripting Guide.

coming soon

I'm working on a script randomly grab mp3s from a playlist and fill a CD with shuffled songs.

I'll be using bash's built-in random number generator which I believe is available in all versions.

Here's the shuffle function for those interested:


# Usage: shuffle <filename>
function shuffle () {

   cat "${@}"|grep -v "^#" | \
   while read mp3 ; do
      echo "$RANDOM $mp3"
   done | sort | cut -d" " -f2-
}

Requirements will be mpg321 and cdrecord.

tagging mp3s

Final installment of the podcast bash script for a while. I will eventually add the ability to auto-sync with my iPod, but I'm still undecided at which command line iPod tools I want to use. Currently gtkpod is doing a great job of keeping my iPod fed, and it's simple to load it up, add my podcast folder and sync. gtkpod weeds out the dupes and automatically transfers just what's needed.

I'm just going to describe the tagmp3 function, much like I did for the updated getmp3 function last time. Read the script to see how I hook the tagmp3 function into getmp3. It could all us a bit more error handling, but it works well enough now to be useful.

I am using id3v2 from here. It is easy to compile and only has one dependency, id3lib. I'm using the id3lib and id3lib-devel RPMs for FC3 from FreshRPMs.

Continue reading