"command not found" errors when executing TCL script in OSX -


i'm trying execute this tcl script, should batch normalise folder of mp3's. i'm on osx yosemite (ffmpeg installed). line is:

./normalise.tcl mp3folder 

which (inc. sudo) returns:

./normalise.tcl: line 37: proc: command not found ./normalise.tcl: line 38: global: command not found ./normalise.tcl: line 40: switch: command not found ./normalise.tcl: line 42: puts: command not found ./normalise.tcl: line 43: syntax error near unexpected token `}' ./normalise.tcl: line 43: `        }' 

.. , directs shell inbuilt documentation. have no experience of language reading up, haven't come across far explain it. grateful idea what's going wrong.


edit

the -d option suggested in script comments seems have no effect.

the full script:

#!/bin/sh #\ exec tclsh "$0" ${1+"$@"}  # copyright 2015 tholis biroi (tholis dot biroi @ yahoo dot it) # # file part of 'normalize.tcl'. # 'normalize.tcl' free software: can redistribute and/or modify  # under terms of gnu general public license published # free software foundation, either version 3 of license, or  # (at option) later version. # 'normalize.tcl' distributed in hope useful,  # without warranty; without implied warranty of  # merchantability or fitness particular purpose.  # # see gnu general public license more details. # should have received copy of gnu general public license  # along 'normalize.tcl'. if not, see http://www.gnu.org/licenses/. # # # # 'normalize.tcl' simple tcl script drives 'ffmpeg' normalise # audio levels group of mp3 files. # each mp3 file found directory, reads mean volume level,  # calculates average level among various files , adjusts volume # level of each of them. #  # global debugging variable # override option set '-d' on command line set debugon false  # log -- # # puts "" wrapper  # proc log {label args} {     global debugon      switch $label {         "info" {             puts {*}$args         }         "error" {             puts "error: [join {*}$args]"          }         "warning" {             puts "warning: [join {*}$args]"          }         "debug" {             if {$debugon == "true"} {                 puts "debug: [join {*}$args]"              }         }         default {             # nothing in case         }     } }   # get_volumes -- # # exec 'ffmpeg' in order volume mean level # # proc get_volume {mp3} {     if {$mp3 == {}} {         log error "empty file name."         return {}     }      # set volume variable     set volume {}      # set 'ffmpeg' command     set cmd "ffmpeg  -i \"$mp3\" -af \"volumedetect\" -f null /dev/null"         log debug "'ffmpeg' cmd= $cmd"      # exec 'ffmpeg'     if {[catch {eval exec -ignorestderr $cmd 2>@1} out]} {         log error "'ffmpeg' execution command failed."         log debug "reason= $out"         return {}     }      # in order avoid 'case sensitive' parsing, output of      # command converted uppercase     set out [string toupper $out]         log debug "'ffmpeg' out= $out"      # scan out line @ time searching 'mean_volume:'      # output string label     set lines [split $out "\n"]      foreach line $lines {         log debug "$line"         # first of search 'volumedetect' string , if foud         # search 'mean_volume:' string.         if {[string first volumedetect $line] == -1} {             # not found, skip line parsing              continue         }          # 'volumedetect' string found, search 'mean_volume' string         set pos [string first mean_volume $line]         if { $pos != -1} {             set start [expr {$pos + 11}]             set volstr [string range $line $start end]             log debug "volstr= $volstr"              # extract , trim first word volume             set words [split $volstr]             log debug "words= $words"             set volume [string trim [lindex $words 1]]             log debug "volume= $volume"         }     }      return $volume } ;# end get_volume   # set_volume -- # # exec 'ffmpeg' re-encode mp3 # proc set_volume {mp3 actualvol targetvol} {     if {($mp3 == {}) || ($actualvol == {}) || ($actualvol == {})} {         log error "one or more parameter empty"         return {}     }      # create filename output     set mp3root [file rootname $mp3]     set mp3outfile "${mp3root}.norm.mp3"      # if normalized file exists, deleted     if {[file exists $mp3outfile]} {         catch {file delete -force -- $mp3outfile}     }      # calculate delta volume     set deltavol [expr {$targetvol - $actualvol}]      # set 'ffmpeg' command     set cmd "ffmpeg -y -i \"$mp3\"  -af \"volume=${deltavol}db\" \"$mp3outfile\""      # exec 'ffmpeg'     if {[catch {eval exec -ignorestderr $cmd 2>@1} out]} {         log error "'ffmpeg' execution command failed."         log debug "reason= $out"         return {}     }         # debug purposes     set out [string toupper $out]         log debug "'ffmpeg' out= $out"      return $deltavol } ;# end set_volume   # byebye -- # proc byebye {} {     log info ""     log info "bye!"     log info "" } ;# end byebye   # print_help -- #  # prints little # proc print_help {} {     global argv0      log info ""     log info "usage: $argv0 \[-h|--help\]|<mp3 dir>"     log info ""     log info "-h|--help  print thi help"     log info "<mp3 dir>  directory path containing mp3 normalize"     log info ""      byebye     return } ;# end print_help  # main ----------------------------------------------------------------- log info "" log info "mp3 normalizer v0.9 21 mar 2015" log info "" log info ""  # save current dir set currdir [pwd] log debug "working dir= $currdir"  # control input parameters setup working dir  # if no parameter passed little printed on screen if {$argc == 0} {     print_help     exit 0 }  # if more 1 parameter passed if {$argc != 1} {     log error "wrong number of arguments."     log error "use '-h' or '--help' option print usage info."      byebye     exit 1 }  # if 1 paramter passed, option or # desired working path if {([lindex $argv 0] == "-h") || ([lindex $argv 0] == "--help")} {     print_help     exit 0 }  # save passed workdir in order make controls set workdir [lindex $argv 0]  # path passed must directory path if { ![file isdirectory $workdir] } {     log error "the argument passed not valid directory path"      byebye     exit 1 }  # argument passed must existing directory if { ![file exists $workdir] } {     log error "directory '$workdir' not exists"      byebye     exit 1 }  # move on working dir cd $workdir  # list of files in current directory set mp3files [glob -nocomplain *.mp3]  if {$mp3files == {}} {     log info "no .mp3 files found on working dir: '$workdir'"      byebye     exit 1 }  # exclude list files exetension *.norm.mp3" set mp3filelist {} foreach mp3 $mp3files {     set rootfname [file rootname $mp3]     set ext [file extension $rootfname]      if {$ext == ".norm"} {         # skip normalized files mp3 list         continue     }      lappend mp3filelist $mp3 }   # init mp3 array #set mp3ar {}  log info "list of file mp3 normalized:"  # foreach *.mp3 file  foreach mp3 $mp3filelist {     log info "   '$mp3'"      # extract volumes     set vol [get_volume $mp3]     if {$vol == {}} {         log warning "no volume information found file: $mp3"     } else {         # fill array of volumes         set mp3ar($mp3) $vol     } }  log info ""  # parray debugging #parray mp3ar  # calculating average volume set avgvol 0 set mp3list  [array names mp3ar] set numfiles [llength $mp3list]  foreach mp3 $mp3list {     set avgvol [expr {$mp3ar($mp3) + $avgvol}] } set avgvolume [expr {$avgvol/double($numfiles)}] set avgvol [format "%0.1f" $avgvolume]  log info "avg volume= $avgvol" log info ""  # foreach file calculate delta volume normalize log info "file normalization @ $avgvol db" foreach mp3 $mp3list {     log info "    '$mp3' $mp3ar($mp3) $avgvol"     if {[set_volume $mp3 $mp3ar($mp3) $avgvol] == {}} {         log info "warning: set volume failed file '$mp3'"     } } log info "" log info "done."  # before exit return run dir cd $currdir  byebye  exit 0 

for reason, script being executed bourne shell (/bin/sh) in entirety, , not tcl. since 2 languages have different syntaxes, gets error messages.

but why happening?

well, key lines these:

#!/bin/sh #\ exec tclsh "$0" ${1+"$@"} 

that's supposed run script bourne shell, , transfer execution tcl (since standard shell exec replaces current process executable). it's based on fact shell doesn't think backslash @ end of line in comment special, , yet tcl treats meaning following line part of comment. different rules.

yet that's failing. i'm guessing problem tclsh isn't on path (really? it's standard part of osx system.) , exec failing , remainder of script therefore being interpreted. more bit strange. you're going via sudo might problem, there ought tclsh in 1 of directories sudo puts on path default (/usr/bin), might not what's going on.

the recommended approach @ point change 3 lines of script use more modern idiom that's single line:

#!/usr/bin/env tclsh 

you can use fully-specified name tclsh in there well. or can try launching code with:

tclsh ./normalise.tcl mp3folder 

that last step way detect if there other problems; overrides lookup of script interpreter , lets focus on happens after that.


Comments