Detecting unused variables...

Hi guys...

The first active code line in AudioScope.sh is set -u .
This causes a complete exit if a variable is used/found but has not been allocated at the start of the program.

However, apart from writing code to do the task, is there a switch to to check which variables have been allocated but have not been used in the remainder of the code?

I have checked the WWW and there is nothing. I have also read the bash manual and can't see any reference.

iMac, OSX 10.11.4, bash version:-

GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)
Copyright (C) 2007 Free Software Foundation, Inc.

Thanks In Advance...

Maybe it helps to grep out the variable assignments from your script?
Here is a clumsy attempt:

script=yourscript
perl -pe 's/.*?([[:alpha:]]\w*)=/$1\n/g; s/[^\n]*$//' $script

Then try to find the $var references in a loop, and print if not found

for var in `perl -pe 's/.*?([[:alpha:]]\w*)=/$1\n/g; s/[^\n]*$//' $script | awk 'NF>0 && s[$0]++==0'`
do
  grep '\${\{0,1\}'"$var"'\>' $script >/dev/null || echo "$var"
done

Yet it does not know if a var= is within a 'string' or "string" i.e. is not an assignment in the shell...

1 Like

Hi.

Found in Debian repository (noted by Is there a static analysis tool like Lint or Perl::Critic for shell scripts? - Stack Overflow ):

#!/usr/bin/env bash

# @(#) s1       Demonstrate static shell checking.
# If not in repository, see:
# http://hackage.haskell.org/package/ShellCheck
# ( Verified 2016.05.14 )

# Utility functions: print-as-echo, print-line-with-visual-space, debug.
# export PATH="/usr/local/bin:/usr/bin:/bin"
LC_ALL=C ; LANG=C ; export LC_ALL LANG
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
db() { ( printf " db, ";for _i;do printf "%s" "$_i";done;printf "\n" ) >&2 ; }
db() { : ; }
C=$HOME/bin/context && [ -f $C ] && $C shellcheck

FILE=${1-data1}

pl " Input data file $FILE:"
cat $FILE

pl " Results:"
shellcheck $FILE

exit 0

producing:

$ ./s1

Environment: LC_ALL = C, LANG = C
(Versions displayed with local utility "version")
OS, ker|rel, machine: Linux, 3.16.0-4-amd64, x86_64
Distribution        : Debian 8.4 (jessie) 
bash GNU bash 4.3.30
ShellCheck - shell script analysis tool

-----
 Input data file data1:
#!/bin/bash

# @(#) example1.sh      Demonstrate catching of errors.

v0=7

for i in 1 2 3
do
  (( l=j+1 ))
  printf " Hello, world (from script)"
done

if [ $v1 ]
then
  echo ' My fault'
fi

exit $n

-----
 Results:

In data1 line 5:
v0=7
^-- SC2034: v0 appears unused. Verify it or export it.


In data1 line 7:
for i in 1 2 3
^-- SC2034: i appears unused. Verify it or export it.


In data1 line 13:
if [ $v1 ]
     ^-- SC2086: Double quote to prevent globbing and word splitting.


In data1 line 18:
exit $n
     ^-- SC2086: Double quote to prevent globbing and word splitting.

Best wishes ... cheers, drl

4 Likes

Hi MadeInGermany...

I have no knowledge of Perl so will have study the syntax.
I did try your two code snippets however and it didn't seem to pick out variables, whether in stand alone or string mode, as a single occurence of said 'string' "var=".

I was expecting to write code but got sample code written for me. Thanks...

Hi drl...

Just come on so not had time to look at and try your code snippets as yet.
I don't intend to alter my style of coding from my very first post of AudioScope.sh even though it may look a little primitive now. I have the bash -n filename switch to check the syntax and that is all I need here.

However as MadeInGermany has suggested 'var=' could be anywhere in any line of the code; but so long as there is only one of them then that particular 'var=' can be considered redundant. I will also check to see if there are two of the said variable(s) just in case there is a reference to a redundant variable inside a comment.

Thanks both so far...

---------- Post updated at 01:56 PM ---------- Previous update was at 01:22 PM ----------

Well used......

ShellCheck � shell script analysis tool

......and it gave these results.

$ shellcheck myscript
 
Line 53:
version=" \$VER: AudioScope.sh_Version_"$ver"_2013-2016_Public_Domain_B.Walker_G0LCU."
                                        ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
 
Line 136:
cygwin=`uname`
       ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 146:
printf "$data" >> /tmp/sinewave.raw
       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 164:
printf "$data" >> /tmp/pulse1.wav
       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 174:
printf "$data" >> /tmp/pulse2.wav
       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 182:
        printf "$data" >> /tmp/0000000000.BIN
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 194:
for wave_form in {0..999}
^-- SC2034: wave_form appears unused. Verify it or export it.
 
Line 196:
        printf "$data" >> /tmp/squarewave.raw
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 250:
printf '#!/bin/bash\n' >> /tmp/1KHz-Test.sh
^-- SC2129: Consider using { cmd1; cmd2; } >> file instead of individual redirects.
 
Line 286:
echo -e -n '@ECHO OFF\r\n' >> /tmp/VERT_BAT.BAT
^-- SC2129: Consider using { cmd1; cmd2; } >> file instead of individual redirects.
 
Line 305:
printf '#!/bin/bash\n' >> /tmp/VERT_SOX.sh
^-- SC2129: Consider using { cmd1; cmd2; } >> file instead of individual redirects.
 
Line 310:
printf '        printf "$data" >> /tmp/squarewave.raw\n' >> /tmp/VERT_SOX.sh
       ^-- SC2016: Expressions don't expand in single quotes, use double quotes for that.
 
Line 329:
printf '#!/bin/bash\n' >> /tmp/VERT_DSP.sh
^-- SC2129: Consider using { cmd1; cmd2; } >> file instead of individual redirects.
 
Line 334:
printf '        printf "$data" >> /tmp/squarewave.raw\n' >> /tmp/VERT_DSP.sh
       ^-- SC2016: Expressions don't expand in single quotes, use double quotes for that.
 
Line 347:
printf "\x1B]0;Shell AudioScope Version "$ver".\x07"
       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
                                         ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
 
Line 363:
        read -n1 -s -t$1
        ^-- SC2162: read without -r will mangle backslashes.
                      ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 400:
        cd /tmp
        ^-- SC2164: Use cd ... || exit in case cd fails.
 
Line 401:
        SoundRecorder.exe \/FILE waveform.wav \/DURATION 0000:00:02
                          ^-- SC1001: This \/ will be a regular '/' in this context.
                                              ^-- SC1001: This \/ will be a regular '/' in this context.
 
Line 402:
        cd ~
        ^-- SC2164: Use cd ... || exit in case cd fails.
 
Line 409:
        . /tmp/AudioScope.config
        ^-- SC1091: Not following: /tmp/AudioScope.config was not specified as input (see shellcheck -x).
 
Line 417:
        printf "demo=$demo\n" >> /tmp/AudioScope.config
        ^-- SC2129: Consider using { cmd1; cmd2; } >> file instead of individual redirects.
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 418:
        printf "drawline=$drawline\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 419:
        printf "sound_card_zero_offset=$sound_card_zero_offset\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 420:
        printf "scan_start=$scan_start\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 421:
        printf "scan_jump=$scan_jump\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 422:
        printf "scan_end=$scan_end\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 423:
        printf "setup='$setup'\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 424:
        printf "save_string='$save_string'\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 425:
        printf "foreground=$foreground\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 426:
        printf "timebase='$timebase'\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 427:
        printf "vertical='$vertical'\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 428:
        printf "polarity=$polarity\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 429:
        printf "capturemode='$capturemode'\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 430:
        printf "capturepath='$capturepath'\n" >> /tmp/AudioScope.config
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 463:
        printf "$graticule"
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 499:
                rm $HOME/Movies/*.aifc > /dev/null 2>&1
                   ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 550:
                        vert=`hexdump -n1 -s$subscript -v -e '1/1 "%u"' /tmp/waveform.raw`
                             ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 553:
                        vert=`od -An -N1 -j$subscript -tu /tmp/waveform.raw`
                             ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 558:
                        vert=$[ ( 255 - $vert ) ]
                             ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 561:
                vert=$[ ( $vert + $sound_card_zero_offset ) ]
                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 571:
                vert=$[ ( ( $vert / 16 ) + $vert_shift ) ]
                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 581:
                subscript=$[ ( $subscript + $scan_jump ) ]
                          ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 584:
                printf "\x1B[1;37;44m\x1B["$vert";"$horiz"f*"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
                                           ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
                                                   ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
 
Line 606:
                subscript=$[ ( $subscript + 1 ) ]
                          ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 609:
                number=$[ ( $vert_two - $vert_one ) ]
                       ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 621:
                                vert_one=$[ ( $vert_one - 1 ) ]
                                         ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 624:
                                        printf "\x1B[1;37;44m\x1B["$vert_one";"$horiz"f*"
                                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
                                                                   ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
                                                                               ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
 
Line 625:
                                        vert_one=$[ ( $vert_one - 1 ) ]
                                                 ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 630:
                                vert_one=$[ ( $vert_one + 1 ) ]
                                         ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 633:
                                        printf "\x1B[1;37;44m\x1B["$vert_one";"$horiz"f*"
                                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
                                                                   ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
                                                                               ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
 
Line 634:
                                        vert_one=$[ ( $vert_one + 1 ) ]
                                                 ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 648:
        printf "\x1B[0;37;40m\x1B[22;3f$blankline\x1B[22;4f"
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 651:
                printf "\x1B[0;$foreground;40mStopped...\x1B[0;37;40m"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 655:
                printf "Running \x1B[0;32;40m$scan\x1B[0;37;40m of \x1B[0;32;40m$scanloops\x1B[0;37;40m scan(s)..."
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 667:
                printf "Synchronisation set to \x1B[0;32;40m$sync_point\x1B[0;37;40m$synchronise..."
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 675:
                printf "\x1B[0;33;40m$zoom\x1B[0;37;40m"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 679:
                printf "Horizontal shift, scan start at position \x1B[0;32;40m$scan_start\x1B[0;37;40m..."
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 683:
                printf "Symmetrical waveform frequency is \x1B[0;32;40m"$freq"\x1B[0;37;40m Hz..."
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
                                                                        ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
 
Line 691:
                printf "$char"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 696:
                printf "\x1B[23;3f$version\x1B[20;14f"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 712:
        read -p "Press <CR> to (re)run, HELP or QUIT<CR>:- " -e kbinput
        ^-- SC2162: read without -r will mangle backslashes.
 
Line 742:
                break
                ^-- SC2104: In functions, use return instead of break.
 
Line 771:
                capturepath=`ls /dev/dsp 2>/dev/null`                
                            ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 783:
                        printf "\x1B[0;31;40m\x1B[22;3f$blankline\x1B[22;4fThe device /dev/dsp does not exist, switching back to DEMO mode...\x1B[20;14f"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 797:
                printf "\x1B[0;37;40m\x1B[22;3f$blankline\x1B[22;4fPlease wait while SOX is found, this \x1B[0;31;40mMIGHT\x1B[0;37;40m take a \x1B[0;31;40mLONG\x1B[0;37;40m time...\x1B[20;14f"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 800:
                capturepath=`find ~ -name 'sox' 2>/dev/null`
                            ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 802:
                char=`which sox 2>/dev/null`
                     ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 818:
                        printf "\x1B[0;31;40m\x1B[22;3f$blankline\x1B[22;4fThe SOX audio device was not found, switching back to DEMO mode...\x1B[20;14f"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 833:
                capturepath=`ls /usr/bin/osascript 2>/dev/null`
                            ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 845:
                        printf "\x1B[0;31;40m\x1B[22;3f$blankline\x1B[22;4fThe MAC audio device was not found, switching back to DEMO mode...\x1B[20;14f"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 859:
                capturepath=`SoundRecorder.exe \/FILE waveform.wav \/DURATION 0000:00:02 > /dev/null 2>&1`
                            ^-- SC2006: Use $(..) instead of legacy `..`.
                                               ^-- SC1001: This \/ will be a regular '/' in this context.
                                                                   ^-- SC1001: This \/ will be a regular '/' in this context.
 
Line 872:
                        printf "\x1B[0;31;40m\x1B[22;3f$blankline\x1B[22;4fThe Windows audio device was not found, switching back to DEMO mode...\x1B[20;14f"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 884:
                capturepath=`ls /usr/bin/arecord 2>/dev/null`
                            ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 896:
                        printf "\x1B[0;31;40m\x1B[22;3f$blankline\x1B[22;4fThe ALSA audio device was not found, switching back to DEMO mode...\x1B[20;14f"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 941:
                read -p "Set timebase starting point. From 0 to $scan_end<CR> " -e tbinput
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 954:
                str_len=$[ ( ${#tbinput} - 1 ) ]
                        ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 961:
                        number=`printf "%d" \'$number`
                               ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 963:
                        if [ $number -le 47 ]
                             ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 968:
                        if [ $number -ge 58 ]
                             ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 988:
                read -p "Set timebase user speed. From 1 to $[ ( ( ( $scan_end - $scan_start ) / 64 ) + 1 ) ]<CR> " -e tbinput
                ^-- SC2162: read without -r will mangle backslashes.
                                                            ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 998:
                str_len=$[ ( ${#tbinput} - 1 ) ]
                        ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1005:
                        number=`printf "%d" \'$number`
                               ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 1007:
                        if [ $number -le 47 ]
                             ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1012:
                        if [ $number -ge 58 ]
                             ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1026:
                number=$[ ( ( ( $scan_end - $scan_start ) / 64 ) + 1 ) ]
                       ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1031:
                printf "\x1B[0;37;40m\x1B[22;4fScan start at offset \x1B[0;32;40m$scan_start\x1B[0;37;40m, with a jump rate of \x1B[0;32;40m$scan_jump\x1B[0;37;40m."
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1215:
                        read -p "Vertical shift:- U for up 1, D for down 1, <CR> to RETURN:- " -n 1 -s vshift
                        ^-- SC2162: read without -r will mangle backslashes.
 
Line 1223:
                                vert_shift=$[ ( $vert_shift + 1 ) ]
                                           ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1227:
                                vert_shift=$[ ( $vert_shift - 1 ) ]
                                           ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1238:
                        printf "\x1B[23;3f Vertical shift is \x1B[0;32;40m$[ ( 2 - $vert_shift ) ]\x1B[0;37;40m from the mid-point position...                        "
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
                                                                          ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1262:
                scan_start=$[ ( $scan_start + 1 ) ]
                           ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1274:
                        break
                        ^-- SC2104: In functions, use return instead of break.
 
Line 1277:
                read -p "Set trigger type, <CR> to disable:- " -e kbinput
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 1287:
                                        grab=`hexdump -n1 -s$subscript -v -e '1/1 "%u"' /tmp/waveform.raw`
                                             ^-- SC2006: Use $(..) instead of legacy `..`.
                                                            ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1290:
                                        grab=`od -An -N1 -j$subscript -tu /tmp/waveform.raw`
                                             ^-- SC2006: Use $(..) instead of legacy `..`.
                                                           ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1292:
                                if [ $grab -eq $sync_point ]
                                     ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1302:
                        for subscript in $( seq $scan_start $scan_end )
                                                ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1306:
                                        grab=`hexdump -n1 -s$subscript -v -e '1/1 "%u"' /tmp/waveform.raw`
                                             ^-- SC2006: Use $(..) instead of legacy `..`.
                                                            ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1309:
                                        grab=`od -An -N1 -j$subscript -tu /tmp/waveform.raw`
                                             ^-- SC2006: Use $(..) instead of legacy `..`.
                                                           ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1311:
                                if [ $grab -lt 128 ]
                                     ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1321:
                        for subscript in $( seq $scan_start $scan_end )
                                                ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1325:
                                        grab=`hexdump -n1 -s$subscript -v -e '1/1 "%u"' /tmp/waveform.raw`
                                             ^-- SC2006: Use $(..) instead of legacy `..`.
                                                            ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1328:
                                        grab=`od -An -N1 -j$subscript -tu /tmp/waveform.raw`
                                             ^-- SC2006: Use $(..) instead of legacy `..`.
                                                           ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1330:
                                if [ $grab -gt 128 ]
                                     ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1349:
                        read -p "Set trigger polarity, +, - or <CR>:- " -e char
                        ^-- SC2162: read without -r will mangle backslashes.
 
Line 1353:
                        printf "\x1B[23;3f$setup"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1373:
                                ext_trig_array=(`hexdump -v -e '1/1 "%u "' /tmp/waveform.raw`)
                                                ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 1379:
                                                if [ ${ext_trig_array[$count]} -eq $sync_point ] && [ ${ext_trig_array[$[ ( $count + 1 ) ]]} -gt $sync_point ]
                                                                                                                       ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1386:
                                                if [ ${ext_trig_array[$count]} -eq $sync_point ] && [ ${ext_trig_array[$[ ( $count + 1 ) ]]} -lt $sync_point ]
                                                                                                                       ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1410:
                savefile=`date +%s`'.BIN'
                         ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 1411:
                cp /tmp/waveform.raw /tmp/$savefile
                                          ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1445:
                savefile=`date +%s`'.BIN'
                         ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 1446:
                cp /tmp/waveform.raw /tmp/$savefile
                                          ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1451:
                read -p "Enter the filename ONLY, not the path:- " -e kbinput
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 1453:
                if [ "$kbinput" == "`ls $kbinput`" ]
                                    ^-- SC2006: Use $(..) instead of legacy `..`.
                                        ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1455:
                        cp $kbinput /tmp/waveform.raw
                           ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1473:
                read -p "Press <CR> to continue:- " -n 1
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 1493:
                        read -p "Horizontal shift, press L, l, R, r, (Q or q to exit):- " -n 1 -s kbinput
                        ^-- SC2162: read without -r will mangle backslashes.
 
Line 1503:
                                        scan_start=$[ ( $scan_start + 64 ) ]
                                                   ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1507:
                                        scan_start=$[ ( $scan_start + 1 ) ]
                                                   ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1511:
                                        scan_start=$[ ( $scan_start - 64 ) ]
                                                   ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1515:
                                        scan_start=$[ ( $scan_start - 1 ) ]
                                                   ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1595:
                        read -p "Remove Arduino if it is connected, then press <CR> to continue:- " -n 1
                        ^-- SC2162: read without -r will mangle backslashes.
 
Line 1599:
                        read -p "Now replace Arduino, then press <CR> to continue:- " -n 1
                        ^-- SC2162: read without -r will mangle backslashes.
 
Line 1611:
                        set -- $coupling_device
                               ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1623:
                                printf "\n\x1B[1;32mArduino board, $coupling_device found, DC facility enabled... \x1B[0m"
                                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1631:
                                printf '/* PDE code for Arduino as a single channel ADC for AudioScope.sh... */\n' >> /tmp/Arduino_9600.pde
                                ^-- SC2129: Consider using { cmd1; cmd2; } >> file instead of individual redirects.
 
Line 1665:
                read -p "Press C<CR> (CHOPPER), F<CR> (COUNTER) or V<CR> (VCO):- " -e altdc
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 1693:
                printf "\x1B[0;32;40m\x1B[22;3f$blankline\x1B[22;4fGenerating the sweep.wav and sweep.raw files, please wait a few seconds...\x1B[20;14f"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1705:
                        printf "$char" >> /tmp/sweeper.raw
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1714:
                                printf "$char" >> /tmp/sweeper.raw
                                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1720:
                                printf "$char" >> /tmp/sweeper.raw
                                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1725:
                str=`cat < /tmp/sweeper.raw`
                    ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 1726:
                count=$[ ( ${#str} - 1 ) ]
                      ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1729:
                        printf "${str:$count:1}" >> /tmp/sweeper.raw
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1730:
                        count=$[ ( $count - 1 ) ]
                              ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 1738:
                printf "\x1B[0;33;40m\x1B[22;3f$blankline\x1B[22;4fAll done, now sweeping from 4KHz to about 85Hz and back...\x1B[20;14f"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1764:
                read -p "5) Press <CR> and note, A, the FIRST voltage reading:- " -n 1
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 1774:
                read -p "7) Press <CR> and note, B, the SECOND voltage reading:- " -n 1
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 1783:
                read -p "9) Press A or B for the LOWEST voltage reading, then <CR> " -e char
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 1797:
                read -p "12) Consult the manual for the full setup proceedure. <CR> to exit:- " -n 1
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 1798:
                char=`which afplay`
                     ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 1803:
                char=`which aplay`
                     ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 1810:
                        printf 'echo "Press Ctrl-C to Quit..."\n' >> /tmp/pulsetest.sh
                        ^-- SC2129: Consider using { cmd1; cmd2; } >> file instead of individual redirects.
 
Line 1855:
                printf "\x1B[0;32;40m\x1B[22;3f$blankline\x1B[22;4fPlaying back the one second capture...\x1B[0;37;40m\x1B[20;14f"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 1873:
                savefile=`date +%s`'.BIN'
                         ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 1874:
                cp /tmp/waveform.raw /tmp/$savefile
                                          ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 1878:
                vert_array=`hexdump -v -e '1/2 "%u "' /tmp/waveform.raw`
                           ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 1945:
        read -p "Press <CR> to continue:- " -n 1
        ^-- SC2162: read without -r will mangle backslashes.
 
Line 1970:
        read -p "Press <CR> to continue:- " -n 1
        ^-- SC2162: read without -r will mangle backslashes.
 
Line 1994:
        read -p "Press <CR> to continue:- " -n 1
        ^-- SC2162: read without -r will mangle backslashes.
 
Line 2009:
                read -p "Sync point:- U for up 1, D for down 1, <CR> to RETURN:- " -n 1 -s sync_input
                ^-- SC2162: read without -r will mangle backslashes.
 
Line 2017:
                        sync_point=$[ ( $sync_point + 1 ) ]
                                   ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2021:
                        sync_point=$[ ( $sync_point - 1 ) ]
                                   ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2032:
                printf "\x1B[23;3f Synchronisation point set to \x1B[0;32;40m$sync_point\x1B[0;37;40m...                                        "
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 2042:
        read -p "Set ZOOM gain, (4 = maximum sensitivity), 1, 2, 3 or 4<CR> " -e kbinput
        ^-- SC2162: read without -r will mangle backslashes.
 
Line 2061:
                                vert=`hexdump -n1 -s$subscript -v -e '1/1 "%u"' /tmp/waveform.raw`
                                     ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 2064:
                                vert=`od -An -N1 -j$subscript -tu /tmp/waveform.raw`
                                     ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 2069:
                                vert=$[ ( 255 - $vert ) ]
                                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2082:
                                vert=$[ ( $vert - 64 ) ]
                                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2083:
                                vert=$[ ( ( $vert / 8 ) + 2 ) ]
                                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2088:
                                vert=$[ ( $vert - 96 ) ]
                                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2089:
                                vert=$[ ( ( $vert / 4 ) + 2 ) ]
                                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2094:
                                vert=$[ ( $vert - 112 ) ]
                                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2095:
                                vert=$[ ( ( $vert / 2 ) + 2 ) ]
                                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2100:
                                vert=$[ ( ( $vert - 120 ) + 2 ) ]
                                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2110:
                        subscript=$[ ( $subscript + $scan_jump ) ]
                                  ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2112:
                        printf "\x1B[1;37;44m\x1B["$vert";"$horiz"f*"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
                                                   ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
                                                           ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
 
Line 2129:
        printf "\x1B[0;37;40m\x1B[22;3f$blankline\x1B[22;4fWorking, please wait...\x1B[20;14f"
               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 2153:
                rm $HOME/Movies/*.aifc > /dev/null 2>&1
                   ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 2164:
                freq_array=(`hexdump -v -e '1/1 "%u "' /tmp/symmetricalwave.raw`)
                            ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 2170:
                        char=`od -An -N1 -j$subscript -tu < /tmp/symmetricalwave.raw`
                             ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 2171:
                        echo $char >> /tmp/temp.txt
                             ^-- SC2086: Double quote to prevent globbing and word splitting.
 
Line 2173:
                char=`cat < /tmp/temp.txt`
                     ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 2192:
                        subscript=$[ ( $subscript + 1 ) ]
                                  ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2208:
                        subscript=$[ ( $subscript + 1 ) ]
                                  ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2223:
                freq=$[ ( $freq + 1 ) ]
                     ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2237:
                        dc_data=`hexdump -n1 -s0 -v -e '1/1 "%u"' /tmp/dcdata.raw`
                                ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 2240:
                        dc_data=`od -An -N1 -j0 -tu /tmp/dcdata.raw`
                                ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 2250:
                dc_data=$[ ( $dc_data * 20 ) ]
                        ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2254:
                        printf "\x1B[19;36f\x1B[1;33;40m$dc_data\x1B[0;37;40m"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 2258:
                        printf "\x1B[19;35f\x1B[1;33;40m$dc_data\x1B[0;37;40m"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 2263:
                        printf "\x1B[19;33f\x1B[1;33;40m$dc_data\x1B[0;37;40m"
                               ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 2310:
                        number=$[ ( $number + 1 ) ]
                               ^-- SC2007: Use $((..)) instead of deprecated $[..]
 
Line 2317:
                printf "\x1B[19;33f\x1B[1;33;40m$char"' Volts +DC'"\x1B[0;37;40m"
                       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
 
Line 2372:
                        savefile=`date +%s`'.BIN'
                                 ^-- SC2006: Use $(..) instead of legacy `..`.
 
Line 2373:
                        cp /tmp/waveform.raw /tmp/$savefile
                                                  ^-- SC2086: Double quote to prevent globbing and word splitting.

$ 

It found wave_form but this is used several times so not quite accurate...
As for the rest my code is designed to be as "bash" backwards compatible as is possible, and I am ignoring the 'printf' statements as errors.

I guess I could change the arithmatic and backticks to up to date methods but as I have quoted I want to keep the style as I originally learnt it, not waht I know now.

I am designing this project around a now 3 year 9 month old MBP OSX 10.7.5 and bash version:-
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
Copyright (C) 2007 Free Software Foundation, Inc.

Thanks drl for the pointer. A good find by you and extremely useful but I had no idea how to search for it...

Again thanks all...

Backwards compatible with what? It's already meant for bash, so I assume you mean sh... You store binary data in shell variables -- I wouldn't trust that to work in anything but brand-name BASH, and very modern BASH at that.

The problems it flags with printf are all legit, btw. What would happen if your binary data included a meaningless % character, just incidentally? printf would bomb, that's what, because % is not meaningless to printf. printf "%s" "$data" avoids that problem.

1 Like

You already have been given very good advice here, so there is little for me to add - which is why i can as well quit pretending to be helpful and start to outright annoy you:

i think you tackle this from the wrong side alltogether!

Every software engineer learns about structured programming and its values and writing reusable pieces of code, yada, yada. But as every experienced software engineer can tell you structurisation - that is, breaking down the code to simple functions - is not only about reusing pieces of code and all the other tenets. One of its greatest benefits is that it breaks down long parts of the code into small manageable "chapters".

A former colleague of mine, principal senior coder in a large software project, even opined that a function - any function - that is longer than a screen full (he uses the same 80x40 xterm windows i prefer) should be broken down into parts, if not for anything else than for clarity of reading. Now, i think this strict stance is a bit of throwing the baby out with the bath water, but i can understand his sentiment. I try to apply this to my shell scripting all the time and - apart from a few exceptions, like commandline handling in scripts with many options - my functions are mostly fitting on one page of the 80x40 xterm i prefer.

Now, shell programming allows for a lot of bad behavior: undeclared variables made out of thin air, no real distinction between locals and globals and so on. I try to always work as strict as possible, meaning:

if i use a variable, i write a "typeset"-statement declaring it, using "typeset -i" if i intend to use it as an integer.

I admit publicly here that i am a devout user of Hungarian Style Notation, adapted to my needs as a shell programmer: i use, for instance, "f" as a prefix for file/directory names, even if there is no real datatype of a "path", whereas strings that can contain whatever are prefixed "ch" ("char" obviously). I also use "l" for switches, even though they are integers but should only contain 0 or 1. But it doesn't matter so much what you use: be consistent with yourself! If you use UPPERCASE for variables (personally i hate that, but that is just me) then ALWAYS use it - not sometimes this way and sometimes the other.

I ALWAYS stay away from that handy "export" keyword and the dot-feature ( . command ) - save for a few carefully selected exceptions. If a function needs a certain value from another function calling it, it has to be in the parameters. This way - usually even before i write that function - i have its "interface": which parameters it needs, which return values it produces, which output it creates - already laid out.

So, to sum it up: if you have thousands of lines of code and cannot keep track of your variables i suppose you should do a major code review and rewrite the parts where you needed a variable-tracker in the first place. After some serious restructuring of the code the need for such tools might just go away.

I hope this helps (ahh well, see above).

bakunin

2 Likes

Hi all...
(Apologies for the delay but I have had other commitments. Also for any typos.)

@bakunin...
(Have you tried the code out at all to see what it does?)

1) I am not a software engineer, but a retired, mere amateur. ;o)
2) This project was for me to learn shell scripting, of which I know much more now than day one.
3) There are many functions inside the program that can't really be made simpler than they are and there are also some simple ones called regularly.
4) There are a lot of variables and all are used, there are no extras that have been found. I like _bash_'s flexibiilty and things that It, along with the Terminal, can do makes life interesting. Along the way I have discovered some strange effects of the hardware that I and I suspect nearly everyone else did not know.
5) Lastly a rewrite of the code would be difficult as it has evolved to become a tool that even I could not have imagined - back at the start of this project I bragged about doing this but never in my wildest dreams did I expect it to get where it is. It HAS had a write up in Linux Format Magazine and this is a shock to the system to say the least.
6) Fimally this script does everything EXCEPT build the external hardware for you...
A) Although unfinished, contains the circuits; so far.
B) Generates ALL necessary files plus have extras that you can use elsewhere as .WAV files.
C) Creates a working Audio Oscilloscope using text mode inside a terminal without the need for fancy graphics.
D) Uses 3 dedicated capture modes, along with 3 other modes that are platform specific.
E) Uses ONLY the mic/ear socket of an MBP 13 inch OSX 10.7.5 using the default bash terminal.
F) It has evolved over time.
G) And LBNL, I don't think this has ever been attempted anywhere elsebefore.
H) Capable of doing both AC and DC measurements to a minimum of 4 - 5 bit depth.
I) Other things that elude me at the moment.

It is designed to run on hopefully UNIX, definitely various Linux flavours in both 32 and 64 bit guises, CygWin and CygWin64 and MBP/iMac OSX 10.7.x minimum.

So to finalise, you have not annoyed me but it would be very difficult to start again with my current knowledge so I am coding this in its original coding style.

A listing of the files generated for the current version:-

-rw-r--r--  1 barrywalker  wheel  48000  5 Jun 13:14 0000000000.BIN
-rwxr--r--  1 barrywalker  wheel    503  5 Jun 13:14 1KHz-Test.sh
-rw-r--r--  1 barrywalker  wheel  80272  5 Jun 13:15 AudioScope.Manual
-rw-r--r--  1 barrywalker  wheel    327  5 Jun 13:15 AudioScope.config
-rw-r--r--  1 barrywalker  wheel    253  5 Jun 13:14 VERT_BAT.BAT
-rw-r--r--  1 barrywalker  wheel    295  5 Jun 13:14 VERT_DSP.sh
-rw-r--r--  1 barrywalker  wheel    336  5 Jun 13:14 VERT_SOX.sh
-rw-r--r--  1 barrywalker  wheel      1  5 Jun 13:14 dcdata.raw
-rw-r--r--  1 barrywalker  wheel  65580  5 Jun 13:15 pulse.wav
-rw-r--r--  1 barrywalker  wheel  65580  5 Jun 13:14 pulse1.wav
-rw-r--r--  1 barrywalker  wheel  65580  5 Jun 13:14 pulse2.wav
-rwxr-xr-x  1 barrywalker  wheel      1  5 Jun 13:14 pulsetest.sh
-rw-r--r--  1 barrywalker  wheel  48000  5 Jun 13:14 sample.raw
-rw-r--r--  1 barrywalker  wheel      1  5 Jun 13:14 signed16bit.txt
-rw-r--r--  1 barrywalker  wheel  65536  5 Jun 13:14 sinewave.raw
-rw-r--r--  1 barrywalker  wheel  65580  5 Jun 13:14 sinewave.wav
-rw-r--r--  1 barrywalker  wheel   8000  5 Jun 13:14 squarewave.raw
-rw-r--r--  1 barrywalker  wheel  65096  5 Jun 13:14 sweep.raw
-rw-r--r--  1 barrywalker  wheel  65140  5 Jun 13:14 sweep.wav
-rw-r--r--  1 barrywalker  wheel  32548  5 Jun 13:14 sweeper.raw
-rw-r--r--  1 barrywalker  wheel   8000  5 Jun 13:14 symmetricalwave.raw
-rw-r--r--  1 barrywalker  wheel  48000  5 Jun 13:15 waveform.raw
-rw-r--r--  1 barrywalker  wheel  65580  5 Jun 13:14 waveform.wav

@Corona688...
OK, maybe backwards compatibilty is not the phrase to use, however I do test on various platforms. Several Linux flavours using live DVDs, iMac and MBP, CygWin and CygWin64 of which the latter did show up a bug NOT even related to printf . I have even used the 'printf' inside /usr/bin/printf which does NOT allow escaped hex values but only octal ones but decided that the hex ones looked neater.

I would like professional opinions on trying it out in their UNIX flavours however, even if you don't like it.

And finally the variables are all used and none are detected as not being allocated during program run.

I hope this clears it up and the next upload will be the AC condition finalised with builds and calibration of the AC vertical axis.

The DC conditions will be much harder, Arduino and the first home built 'ALTDC' are done and coded for but not calibrated yet.

Well guys I have done some some experiments printf .
(All 'printf' statements now changed inside AudioScope.
Now consider the code below:-

#!/bin/sh --posix
clear
x=8
y=2
printf "\x1B["$y";"$x"fWorks but is not POSIX or sh compliant...\n"
y=4
printf "%b" "\x1B["$y";"$x"fWorks but is not POSIX or sh compliant...\n"
y=6
printf "%b" "\x1B[""$y"";""$x""fWorks but is POSIX and sh compliant...\n"
y=8
printf "%b" "\x1B[$y;$x""fWorks but is POSIX and sh compliant...\n"
y=10
printf "%b" "\x1B[$y;$xfDoes not work for obvious reasons but it is POSIX or sh compliant.\n"
y=12
printf "%b" "\x1B[""$y"';'"$x""fWorks but is POSIX and sh compliant...\n"
y=14
# Why is line 5 not posix complaint but line 18 is?
printf "%b" "\x1B["$y';'$x"fWorks but is POSIX and sh compliant...\n"
exit 0

Results from 'ShellCheck':-

$ shellcheck myscript
 
Line 5:
printf "\x1B["$y";"$x"fWorks but is not POSIX or sh compliant...\n"
       ^-- SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
              ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
                   ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
 
Line 7:
printf "%b" "\x1B["$y";"$x"fWorks but is not POSIX or sh compliant...\n"
                   ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
                        ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
 
Line 13:
printf "%b" "\x1B[$y;$xfDoes not work for obvious reasons but it is POSIX and sh compliant.\n"
                     ^-- SC2154: xfDoes is referenced but not assigned.

$ 

Now line 13 is obviously wrong so ignore that but why is line 5 NOT posix compliant but line 18 IS compliant?
Most of the AudioScope.sh printf statements follow the line 9 format...
Terminal results; OSX 10.7.5, default terminal calling 'sh'.

       Works but is not POSIX or sh compliant...

       Works but is not POSIX or sh compliant...

       Works but is POSIX and sh compliant...

       Works but is POSIX and sh compliant...
ot work for obvious reasons but it is POSIX or sh compliant.


       Works but is POSIX and sh compliant...

       Works but is POSIX and sh compliant...
AMIGA:barrywalker~/Desktop/Code/Shell> _

TIA...

In line 5 the expansions $x and $y are not quoted. If the expansion of $x or $y contains any IFS field separator characters, your format string argument to printf will terminate at the 1st whitespace character in the resulting set of strings passed to printf by the shell after the shell expands those variables.

When a variable name in a variable expansion is followed by characters that could be part of a variable name, use:

"${variable}other text"

instead of:

"$variableother text"

You don't have to quote and unquote every reference to a variable in a quoted string. The following all have exactly the same results in a shell script:

"$v1 $v2 ${v3}text"
"$v1"" ""$v2"" ""${v3}""text"
"$v1"" ""$v2"" ""$v3""text"
"$v1"' '"$v2"' '"${v3}"'text'
"$v1"' '"$v2"' '"$v3"'text'

The normal way to write the printf command:

printf "%b" "\x1B["$y';'$x"fWorks but is POSIX and sh compliant...\n"

even though the above will not do what you want if $y or $x expands to a string containing any whitespace characters (since both expansions are unquoted), is:

printf '\x1B[%s;%sfWorks and is POSIX and sh compliant...\n' "$y" "$x"

which will work correctly even if $x and $y expand to strings that contain percent signs and/or whitespace characters.

1 Like

Thank you Don...

Your explanation is thorough and finding this sort of information on the WWW is near impossible.

It looks lke I will have to go through the AudioScope code again and clean up. There are only a few lines that contain variables to be expanded.
(BTW I meant to quote line 7 and line 18 - NOT 5. Humble apologies...)

I still don't quite understand why ShellCheck rejects:-
printf "%b" "\x1B["$y";"$x"fWorks but is not POSIX or sh compliant...\n"
But accepts:-
printf "%b" "\x1B["$y';'$x"fWorks but is POSIX and sh compliant...\n"

The only difference is ";" and ';' .

I would probably never have found this as 'x' and 'y' will always be integers.
Once again you have put me on the straight and narrow.
Finally, do I assume that the line below is not a valid posix 'printf' statement as it is lacking the '%b'?

 printf "\x1B[0;34;43mIs this a valid posix compliant line?"

It does work in 'sh' on this MBP, OSX 10.7.5 default terminal running sh.
(It seems '%b' is a default modifier for 'printf'.)
Finally thanks again...

I will make the wild assumption that ShellCheck is just checking the printf utility format string operand (and perhaps checking that there are enough operands supplied to match %format-specifier and * in %*.*format-specifier occurrences in the format string operand). Since a format string can be reused if more operands are present than format specifiers, it would be a lot harder for it to determine when an unquoted shell variable is expanded in an operand is wrong versus when an unquoted shell variable in a format string could cause early termination of the format string.

No. There is nothing wrong with this this printf command (other than the fact that it won't do what you want on a machine using an EBCDIC codeset and will only work on certain output devices that understand the escape sequence you have encoded at the start of that output). There are no variables in that format string that could be expanded to require additional operands. That command (with double-quotes as you used them or with the double-quotes replaced by single-quotes) produces a partial line of output that is perfectly well-formed. And, since that format string operand contains no percent sign characters, the following commands would also be valid commands producing exactly the same output (more slowly):

printf '%s' '\x1B[0;34;43mIs this a valid posix compliant line?'
printf '%s' '\x1B[0;34;43mIs this a valid posix compliant line?'

(and, in both of those commands the 1st two single-quotes can be changed to double-quotes and the last two single-quotes can be changed to double-quotes with no difference in the output (but it will run slightly more slowly)).

1 Like

(Bringing it back to the title.)

Hi Don et al...

Since you guys have given valid crticism of AudioScope.sh it has made me look more deeply into posix compliance, so......

I typed this directly into ShellCheck and got the bizarre results below.
It means I have to check absolutelty everything from variable constructs to printing to 'STDOUT'.
It looks like ShellCheck successfully finds any variables that seem unused; however...
Ignore the printf STDOUT printing _errors_ that could be produced as I am now fully aware of those...

#!/bin/sh
x='A string.'
y='Another string.'
text='\x1B[0m'$y' '$x'These variables look OK!'
texts="1x1B[0m"$y' '$x"These variables look OK too!."
txt='\x1B[0m'$y" "$x'These variables look OK also!'
txts="\x1B[0m"$y" "$x"This is bizarre, why the inverted commas error?"
$ shellcheck myscript
 
Line 4:
text='\x1B[0m'$y' '$x'These variables look OK!'
^-- SC2034: text appears unused. Verify it or export it.
 
Line 5:
texts="1x1B[0m"$y' '$x"These variables look OK too!."
^-- SC2034: texts appears unused. Verify it or export it.
 
Line 6:
txt='\x1B[0m'$y" "$x'These variables look OK also!'
^-- SC2034: txt appears unused. Verify it or export it.
 
Line 7:
txts="\x1B[0m"$y" "$x"This is bizarre, why the inverted commas error?"
^-- SC2034: txts appears unused. Verify it or export it.
              ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.
                   ^-- SC2027: The surrounding quotes actually unquote this. Remove or escape them.

$ 

I have made a rod for my own back here...

Thanks to Don all for your input...

Hi wisecracker,
There are lots of things to consider here. Strings used in variable assignments follow slightly different rules than strings used in other shell operations (such as command-line arguments to utilities). See the following script for example:

#!/bin/sh
a=" after"
b="before "
m=" middle "
x=' a b '
y=' echo d '
unset v1 v2
# Note that the expandsion of $y and $x in the next statement are not quoted.
v1="before"$y" "$x"after"
printf '"v1":X%sX\n' "$v1"
printf 'v1:X%sX\n' $v1

# Note that the strings to which $y and $x are substituted here, but not as
# variable expansions.  Here "echo" becomes a command to execute with v2 set as
# a variable in the environment of the echo command, but it is not set in the
# current shell execution environment.
v2="before" echo d " " a b "after"
printf '"v2":X%sX\n' "$v2"
printf 'v2:X%sX\n' $v2

# Now see how those same sets of strings are handled when passed as arguments to
# a utility instead of being assigned to a variable...
printf 'v1string:X%sX\n' "before"$y" "$x"after"
printf 'v2string:X%sX\n' "before" echo d " " a b "after"

# Spaces still matter when variable expansions are separated by IFS characters.
set -xv
w=$b $m $a
z=$b$m$a
set +xv
# And, of course leading and trailing spaces disappear when fields are separated
# in unquoted arguments.
printf 'space between:X%sX\n' $b $m $a
printf 'no space between:X%sX\n' $b$m$a

which produces the output:

"v1":Xbefore echo d   a b afterX
v1:XbeforeX
v1:XechoX
v1:XdX
v1:XaX
v1:XbX
v1:XafterX
d   a b after
"v2":XX
v2:XX
v1string:XbeforeX
v1string:XechoX
v1string:XdX
v1string:X X
v1string:XaX
v1string:XbX
v1string:XafterX
v2string:XbeforeX
v2string:XechoX
v2string:XdX
v2string:X X
v2string:XaX
v2string:XbX
v2string:XafterX
w=$b $m $a
+ w='before '
+ middle after
tester: line 28: middle: command not found
z=$b$m$a
+ z='before  middle  after'
set +xv
+ set +xv
space between:XbeforeX
space between:XmiddleX
space between:XafterX
no space between:XbeforeX
no space between:XmiddleX
no space between:XafterX

So, in your statement:

txts="\x1B[0m"$y" "$x"This is bizarre, why the inverted commas error?"

it does what you want even though the expansions $y and $x are not quoted (because it is an assignment statement). But, why are you adding the extra double-quotes? They don't do anything but make the code harder to read. Variable expansions, command substitutions, and arithmetic expansion are all processed in double-quoted strings, so why not simplify your code and make it easier to read and understand:

txts="\x1B[0m$y ${x}This is bizarre, why the inverted commas error?"

(which is a single double-quoted string). Or, if you are really against using braces to keep variable names separate from following text:

txts='\x1B[0m'"$y $x"'This is bizarre, why the inverted commas error?'

(which has the constant characters in the two single-quoted strings and the variable expansions in a single double-quoted string).
And, besides being easier to read and understand, I would think either of these should make shellcheck happy too. (But I don't have shellcheck installed on my system; so I haven't verified that.)

I should also have mentioned in earlier posts on this subject that \x followed by two hexadecimal digits is a common extension provided by many implementations of the printf utility (both stand-alone and as shell built-ins), but it is not mentioned in the standards. Similarly, \e is a common extension that expands to an escape character in the current locale provided by many implementations of the printf utility, but it is not mentioned in the standards either. With any standards conforming version of printf , you can use the octal escape sequence \033 to specify an escape character in locales with an underlying codeset that is a superset of ASCII.

This may help:

     +-------+  +-+  +-----------------------------------------------+
     v       v  v v  v                                               v
txts="\x1B[0m"$y" "$x"This is bizarre, why the inverted commas error?"

The shell maintains only a single switch for "inside a quoted string" which can be true or false. Therefore it is not possible to nest any quotations. We have often the misunderstanding here that it works like this:

+-----------------+
|    +------+     |
v    v      v     v
"    '      '     "

That is: a single-quoted string inside a double-quoted string. The truth is it is like this:

+-----------------+
v                 v
"    '      '     "

because the single-quotes lose their special meaning as quoting characters inside a quoted string. The shell, upon encountering the first double quote, flips its flag to "inside a quoted string" and it takes every character literally until encountering the second double-quote, when it flips the flag back to "outside a quoted string".

There is actually only a single exception to this rule and it happens with subshells:

echo "foo$(command "arg1" "arg2")bar"

is actually one double-quoted string "foo<something>bar", where <something> is the output of the command command "arg1" "arg2" .

One more word about your escape-sequences: You might make your script a lot more flexible by using the respective terminals escape-queneces instead of using fixed ones. I haven't looked up what \x1B[0m is for, but lets suppose it is for moving the cursor to row 0, col 0. A better way would be to do it like this:

chHome="$(tput home)"          # query TERMINFO database for sequence to home cursor

[...]
printf "%sThis text starts in left upper corner.\n" "$chHome"

I hope this helps.

bakunin

POSIX compliance is a little high to shoot for when storing binary data inside shell variables, you're not going to get it. This is a BASH script and liable to stay that way. But it can be made a better BASH script.

The question isn't really about compliance, it's about avoiding unintended problems. printf "$randomstring" will mess up whenever $randomstring contains an unintentional % character as those have special meaning to printf. pritnf "%s" "$string" avoids this, but at the cost of not expanding "\x" sequences etc inside $string.

Hi guys...

Sorry about the long delay, I am a carer now for my mother so get very little time to do anything WRT programming.

I don't think AudioScope.sh is capable of being purely 'shell', (sh), able because of the 'read' statement.

I need the '-t[secs]' argument and reading the POSIX information on here the 'shell' will only allow the '-r' argument.

It also looks like 'bash' is not recognised either or I may be missing something.

So I will be cleaning up the code to suit current methods and 'bash' only, much of which I have already done.

Thanks for the input...

Another AudioScope.sh upload soon.

Hi.

On an old Mac:

OS, ker|rel, machine: Apple/BSD, Darwin 9.8.0, Power Macintosh
Distribution        : Mac OS X 10.5.8 (leopard, workstation)
bash GNU bash 3.2.17

I see in man bash:

read [-ers] [-u fd] [-t timeout] [-a aname] [-p prompt] [-n nchars] [-d delim] [name ...]

However, you might find useful:

qprompt, timer, specific characters, prompt-string, etc.; in c
           http://www.ibiblio.org/pub/historic-linux/ftp-archives/sunsite.unc.edu/Nov-06-1994/utils/shell/qprompt-2.3.tar.gz
           ( Verified 2016.06.20, compiles with warning, worked in 64-bit )

Best wishes ... cheers, drl

Hi drl...

With the pointer to ShellCheck giving more than required by this thread and does what I need then this thread is solved.

Thanks.