linux - Bash script errors

08
2014-07
  • Desd

    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:

    1. /home/jeroen/bpmtagging.sh: line 67: warning: here-document at line 4 delimited by end-of-file (wantedHELP')`
    2. /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
    
  • Answers
  • slhck

    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:


  • Related Question

    ubuntu - Why is bash rsync script not writing anything to file?
  • user19496

    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 ?


  • Related Answers
  • Dennis Williamson

    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.

  • Gilles

    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