I'm trying to create a script in Bash to call an executable with a large set of arguments. To improve readability, I'm grouping different sets of arguments into variables, and passing those variables to the executable.
The issue I'm having is that Bash seems to evaluate the flags improperly when I pass them through a variable to the executable than when I pass them directly. I'd like to be able to pass any type of flag via a variable if I want, even if it requires quotes.
Passing Arguments Directly
I find that if I do this, then the script works and I get the expected output:
$LINT_EXECUTABLE \
$SYSTEM_INCLUDES \
$RTE_INCLUDES \
$SRC_INCLUDES \
$LINT_CONFIG_INCLUDES \
$OBJECT_INCLUDES \
$INDIRECT_FILES \
-format="*** LINT: %(%f(%l) %)%t %n: %m" \
src/**/*.c
Output
--- Module: src\c\error.c (C)
Including file src/include\error.h (hdr)
*** LINT: src/include\error.h(8) note 9071: defined macro '__ERROR_H' matches a
pattern reserved to the compiler [MISRA 2012 Rule 21.1, required]
#define __ERROR_H
// ...
Passing Arguments Through Variables
However, if I do this, then I end up with improper output:
OPTIONS="-format=\"*** LINT: %(%f(%l) %)%t %n: %m\""
$LINT_EXECUTABLE \
$SYSTEM_INCLUDES \
$RTE_INCLUDES \
$SRC_INCLUDES \
$LINT_CONFIG_INCLUDES \
$OBJECT_INCLUDES \
$INDIRECT_FILES \
$OPTIONS \
src/**/*.c
Output
$ ./lint.sh
PC-lint Plus 1.1 TRIAL for Windows, Copyright Gimpel Software LLC 1985-2018
LICENSED FOR EVALUATION USE ONLY
evaluation license expires in 17 days
"***
LINT:
^
What I've Tried
I've tried substituting the escaped double quotes in the Bash variable with single quotes, but that made no difference. I also temporarily set LINT_EXECUTABLE
to echo
to print the evaluated set of arguments to the command-line when running $ ./my-script.sh
.
In the case of passing flags directly, I see it output ... -format=*** LINT: %(%f(%l) %)%t %n: %m
(i.e. no quotes around the -format
value) but if I pass the flag via a variable, I see ... -format="*** LINT: %(%f(%l) %)%t %n: %m" ...
instead.
Environment
I'm running this on a Windows 64-bit machine using the latest version of bash available in Cygwin:
$ bash --version
GNU bash, version 4.4.12(3)-release (x86_64-unknown-cygwin)
Edit
To clarify, OPTIONS
will hold more than just the -format
flag. Right now I define it as:
OPTIONS="
+libh(co-arm_TLE9844_AppKit.h) \
-header(co-arm_TLE9844_AppKit.h) \
-wlib(4) \
-wlib(1) \
+libdir(C:/Keil_v5/ARM/ARMCC/include) \
-hsfb^3 \
-format=\"*** LINT: %(%f(%l) %)%t %n: %m\" \
-width(160,4)"
In response to the suggestion to quote the variable as "$OPTIONS", I tried this but it gave me a different (but still incorrect) output:
$LINT_EXECUTABLE \
$SYSTEM_INCLUDES \
$RTE_INCLUDES \
$SRC_INCLUDES \
$LINT_CONFIG_INCLUDES \
$OBJECT_INCLUDES \
$INDIRECT_FILES \
"$OPTIONS" \
src/**/*.c
This is the evaluated arguments that would get passed to the executable doing this:
$ ./lint.sh
-iC:/Keil_v5/UV4/Lint -iC:/Keil_v5/ARM/ARMCC/include -iC:/Keil_v5/ARM/PACK/ARM/CMSIS/5.3.0/CMSIS/Include -iC:/Keil_v5/ARM/PACK/Infineon/TLE984x_DFP/1.1.1/Device/Include -i./RTE/Device/TLE9844-2QX -i./RTE/_TLE9844_AppKit -i./src/include -i./src/include/drivers -i./src/include/utils -i./config/linting -i./Objects ./config/linting/co-ARMCC-5.lnt ./config/linting/std.lnt
+libh(co-arm_TLE9844_AppKit.h) -header(co-arm_TLE9844_AppKit.h) -wlib(4) -wlib(1) +libdir(C:/Keil_v5/ARM/ARMCC/include) -hsfb^3 -format="*** LINT: %(%f(%l) %)%t %n: %m" -width(160,4) src/c/error.c src/c/main.c ... (other files)
I've used shellcheck.net as recommended and wrapped all my variables in quotes as suggested. This is the latest iteration of my script:
#!/bin/bash
LINT_EXECUTABLE="pclp64"
SYSTEM_INCLUDES="
-iC:/Keil_v5/UV4/Lint \
-iC:/Keil_v5/ARM/ARMCC/include \
-iC:/Keil_v5/ARM/PACK/ARM/CMSIS/5.3.0/CMSIS/Include \
-iC:/Keil_v5/ARM/PACK/Infineon/TLE984x_DFP/1.1.1/Device/Include"
RTE_INCLUDES="
-i./RTE/Device/TLE9844-2QX \
-i./RTE/_TLE9844_AppKit"
SRC_INCLUDES="
-i./src/include \
-i./src/include/drivers \
-i./src/include/utils"
LINT_CONFIG_INCLUDES="
-i./config/linting"
OBJECT_INCLUDES="
-i./Objects"
INDIRECT_FILES="
./config/linting/co-ARMCC-5.lnt \
./config/linting/std.lnt"
OPTIONS="
+libh(co-arm_TLE9844_AppKit.h) \
-header(co-arm_TLE9844_AppKit.h) \
-wlib(4) \
-wlib(1) \
+libdir(C:/Keil_v5/ARM/ARMCC/include) \
-hsfb^3 \
-format=\"*** LINT: %(%f(%l) %)%t %n: %m\" \
-width(160,4)"
$LINT_EXECUTABLE \
"$SYSTEM_INCLUDES" \
"$RTE_INCLUDES" \
"$SRC_INCLUDES" \
"$LINT_CONFIG_INCLUDES" \
"$OBJECT_INCLUDES" \
"$INDIRECT_FILES" \
"$OPTIONS" \
src/**/*.c
Shellcheck.net reports no issues with this script now, but the script fails a lot earlier when I try to execute it:
$ ./lint.sh
PC-lint Plus 1.1 TRIAL for Windows, Copyright Gimpel Software LLC 1985-2018
LICENSED FOR EVALUATION USE ONLY
evaluation license expires in 17 days
<command line> 2 error 305: unable to open module '-iC:\Keil_v5\UV4\Lint
-iC:\Keil_v5\ARM\ARMCC\include
-iC:\Keil_v5\ARM\PACK\ARM\CMSIS\5.3.0\CMSIS\Include
-iC:\Keil_v5\ARM\PACK\Infineon\TLE984x_DFP\1.1.1\Device\Include'