linux - Bash script errors
2014-07
I am trying to get all my MP3 to have the BPM registered. I did find software for that via this Super User question.
I installed bpmdj, vorbis-tools flac python-mutagen
and copied the bash script from the named Super User question (see below). Now, the problem is that this script gives me two errors:
/home/jeroen/bpmtagging.sh: line 67: warning: here-document at line 4 delimited by end-of-file (wanted
HELP')`/home/jeroen/bpmtagging.sh: line 68: syntax error: unexpected end of file
These are the last two lines of the script. I assume the script did work for the OP, but now no longer works on Ubuntu 12.04.
I am new to bash scripting, and I tried to find the errors, but to no avail. Any help would be appreciated.
#!/bin/bash
function display_help() {
cat <<-HELP
Recursive BPM-writer for multicore CPUs.
It analyzes BPMs of every media file and writes a correct tag there.
Usage: $(basename "$0") path [...]
HELP
exit 0
}
[ $# -lt 1 ] && display_help
#=== Requirements
requires="bpmcount mid3v2 vorbiscomment metaflac"
which $requires > /dev/null || { echo "E: These binaries are required: $requires" >&2 ; exit 1; }
#=== Functions
function bpm_read(){
local file="$1"
local ext="${file##*.}"
declare -l ext
# Detect
{ case "$ext" in
'mp3') mid3v2 -l "$file" ;;
'ogg') vorbiscomment -l "$file" ;;
'flac') metaflac --export-tags-to=- "$file" ;;
esac ; } | fgrep 'BPM=' | cut -d'=' -f2
}
function bpm_write(){
local file="$1"
local bpm="${2%%.*}"
local ext="${file##*.}"
declare -l ext
echo "BPM=$bpm @$file"
# Write
case "$ext" in
'mp3') mid3v2 --TBPM "$bpm" "$file" ;;
'ogg') vorbiscomment -a -t "BPM=$bpm" "$file" ;;
'flac') metaflac --set-tag="BPM=$bpm" "$file"
mid3v2 --TBPM "$bpm" "$file" # Need to store to ID3 as well :(
;;
esac
}
#=== Process
function oneThread(){
local file="$1"
#=== Check whether there's an existing BPM
local bpm=$(bpm_read "$file")
[ "$bpm" != '' ] && return 0 # there's a nonempty BPM tag
#=== Detect a new BPM
# Detect a new bpm
local bpm=$(bpmcount "$file" | grep '^[0-9]' | cut -f1)
[ "$bpm" == '' ] && { echo "W: Invalid BPM '$bpm' detected @ $file" >&2 ; return 0 ; } # problems
# Write it
bpm_write "$file" "${bpm%%.*}" >/dev/null
}
NUMCPU="$(grep ^processor /proc/cpuinfo | wc -l)"
find $@ -type f -regextype posix-awk -iregex '.*\.(mp3|ogg|flac)' \
| while read file ; do
[ `jobs -p | wc -l` -ge $NUMCPU ] && wait
echo "$file"
oneThread "$file" &
done
The script contains a heredoc, which is <<-HELP
. It allows you to include literal strings between two identifiers. This identifier is specified after the <<
, and it's HELP
.
In the script you have, there's a special syntax element with a -
between <<
and the identifier. It allows the identifier to be recognized even if it's indented by tabs, so you could write:
cat <<-HELP
some indented text
___HELP
Here, ___
would be a tab. Now, in your case, it's probably indented by multiple spaces, which is why the end of the heredoc isn't found.
There are two solutions for this:
- Change your indentation from spaces to tabs.
- Move the
HELP
identifier to the start of the line.
If you use an editor with proper syntax highlighting (or one that shows spaces vs. tabs), you should see this error:
Ubuntu 9.10
crontab -l
0 1 * * * /root/cron/rsync-93.193.99.111 &> /root/cron/rsync-93.193.99.111.log
0 3 * * * tail -100 /root/cron/rsync-93.193.99.111.log | msmtp [email protected]
ls -l /root/cron/rsync-93.193.99.111.log
-rw-r--r-- root root /root/cron/rsync-93.193.99.111.log
The rsync-93.193.99.111.log file displays zero size in Nautilus.
I get an email, but it's empty.
Running tail -100, also shows emtpty output, so the email is correct.
Why is the bash rsync script not writing anything to the file ?
I believe it's because &>
is not supported in sh
which is the shell that cron
uses. Use the explicit form:
0 1 * * * /root/cron/rsync-93.193.99.111 > /root/cron/rsync-93.193.99.111.log 2>&1
Also, you can do sudo crontab -e
instead of doing sudo su
then crontab -e
.
I concur with Dennis's assessment of your problem. But I have a couple of other points to mention.
Most importantly, don't do this:
0 1 * * * some command
0 3 * * * some other command that should run after the first one
What if the first command takes more or less than two hours? To make sure that the second command runs when the first finished, put them on a single line:
0 1 * * * /root/cron/rsync-93.193.99.111 >/root/cron/rsync-93.193.99.111.log 2>&1; tail -100 /root/cron/rsync-93.193.99.111.log | msmtp [email protected]
Also, you might want to take advantage of cron's automatic mailing of errors. (This assumes your system is set up properly for mail, which may not be the case if you have to run msmtp
rather than mail
.)
MAIL=[email protected]
0 1 * * * /root/cron/rsync-93.193.99.111 2>&1 | tee /root/cron/rsync-93.193.99.111.log | tail -n 100