Search code examples
bashif-statementawkargumentsoption-type

How do I check an if statement for a true/false value in bash?


I'm trying to get option -t below to run if passed to the script ./sample12.sh -t, but now if I pass options -s and -c ./sample12.sh -s 0-9 -c 0-3 I get:

[root@usreliance Biorad]# ./sample12.sh -s 0-9 -c 0-3
Total Samples: 374371

and the output should look like this:

[root@usreliance Biorad]# ./sample12.sh -s 0-9 -c 0-3
                Ch0     Ch1     Ch2     Ch3
Sample 0:       0x1a03  0x1a03  0x4a03  0x5703
Sample 1:       0x4b03  0x4403  0x1e03  0x0904
Sample 2:       0x1003  0x1903  0x4003  0xae03
Sample 3:       0x1e03  0x2603  0x3303  0xad03
Sample 4:       0x1003  0x8403  0x4303  0x6203
Sample 5:       0xe003  0x1603  0x3403  0xc403
Sample 6:       0xf802  0x3b03  0x5303  0x6103
Sample 7:       0x1003  0x1503  0x4203  0x5803
Sample 8:       0x2303  0x1f03  0x5703  0x6203
Sample 9:       0x1703  0x7303  0x3103  0x3303

Here is the script in the state where I'm stuck right now:

#!/usr/bin/env bash

samps=""
chans=""
total=false

while getopts ':c:s:t' opt; do
    case $opt in
        s) samps="$OPTARG" ;;
        c) chans="$OPTARG" ;;
        t) total=true ;;
        *) printf 'Unrecognized option "%s"\n' "$opt" >&2
    esac
done
shift $(( OPTIND - 1 ))

if [ $total ]; then
  printf "Total Samples: "$(hexdump -v -e '8/1 "%02x " "\n"' samples.bin | wc -l)"\n"
else {
  hexdump -v -e '8/1 "%02x " "\n"' samples.bin |
  awk -v samps="$samps" -v chans="$chans" '
    BEGIN {
      # split sample string to arrays using "-" as delimiter
      split(samps, srange, "-")
      # split channel string
      split(chans, crange, "-")

      # arbitrary INT_MAX
      int_max=2^52
      # default 4 channels as per prerequisite example
      chan_default=4

      # set default samples
      if (!srange[1]) srange[1] = 0
      if (!srange[2]) srange[2] = int_max
      # set default channels
      if (!crange[1]) crange[1] = 0
      if (!crange[2]) crange[2] = crange[1] + chan_default-1

      # print channel header row
      printf "\t\t"
      for (i=crange[1]; i<=crange[2]; i++) {
        printf("Ch%d%s", i, (i==crange[2]?"\n":"\t"))
      }
    }
    {
      if(NR >= srange[1] + 1 && NR <= srange[2] + 1) {
        start=(crange[1] + 1) * 2 - 1
        end=(crange[2] + 1 ) * 2

        # print sample range
        printf("Sample %d:\t", NR-1)

        # print channel range in sample line
        for (i = start; i <= end; i+=2) {
            j = i + 1
            printf("0x%s%s%s", $i, $j, (i==end||j==end?"\n":"\t"))
        }
      }
    }
  '
}
fi

Solution

  • The simplest fix is to use the method mentioned by j_b, just use:

    if [[ "$total" == "true" ]]; then
    

    This allows it to compare the strings, "true" as assigned against the literal "true" in the if statement.

    A note on the difference between test, [, and [[. The binary /bin/test and /bin/[ are both able compare values and verify file types. When bash, sh, and zsh encounter these in if statements, they execute the binary. However the [[ is a shell built in for bash and zsh. The shell does not fork() to run a binary. All the checks are handled as a builtin. This is a performance enhancement, but can also be a safety net for bad inputs. When you know you are targeting a shell that supports [[, use it. Interestingly, [ is also a builtin feature for bash.

    Another way to resolve this issue would be to work on numbers instead.

    total=0
    ...
            t) total=1 ;;
    ....
    if [ $total -gt 0 ]; then