0

I want to pass a string parameter to a Bash procedure. This procedure prints the string on console and prints a copy to a file.

In my use case, this file will contain a list of all executed commands in a Bash script that can be used to rerun all instructions in the same order. This is needed if an error occurs and I need to send a reproducer script to an open sourc project on GitHub. It will also copy all used files into a directory for later ZIP file creation.

So, let's talk Bash code:

#! /bin/bash
open() {
    local File=$1
    exec 3<> "$File"
}

close() {
    exec 3>&-
}

procedure1() {
    echo "$1"
    echo "echo \"$1\"" >&3
}

procedure2() {
    echo "$1" "$2"
    echo "echo \"$1\" \"$2\"" >&3
}

procedure3() {
    echo "$@"
    echo "echo \"$@\"" >&3
}

# ==============================================================================
OUTPUT_FILE="output.sh"

Program_A="foo"
Paramater_A=(
    --spam
    --egg=4
)

Program_B="bar"
Paramater_B=(
    --ham
    --spice=4
)

open $OUTPUT_FILE

echo "$Program_A -a ${Paramater_A[@]}"
echo "$Program_B -b ${Paramater_B[@]}"
echo
procedure1 "$Program_A -a ${Paramater_A[@]}" "$Program_B -b ${Paramater_B[@]}"
procedure2 "$Program_A -a ${Paramater_A[@]}" "$Program_B -b ${Paramater_B[@]}"
procedure3 "$Program_A -a ${Paramater_A[@]}" "$Program_B -b ${Paramater_B[@]}"

close

echo
echo -e "\e[33m========================================\e[0m"
echo -e "\e[33mReading output file from disk\e[0m"
echo -e "\e[33m========================================\e[0m"
echo
cat $OUTPUT_FILE

The console output is this:

$ ./test.sh
foo -a --spam --egg=4
bar -b --ham --spice=4

foo -a --spam
foo -a --spam --egg=4
foo -a --spam --egg=4 bar -b --ham --spice=4

========================================
Reading output file from disk
========================================

echo "foo -a --spam"
echo "foo -a --spam" "--egg=4"
echo "foo -a --spam --egg=4 bar -b --ham --spice=4"

So what I see is, that ".... ${Parameter_A[@]} ..." is contained in a string, but breaks the string into multiple strings. That's Why $1 in the procedure contains the string including the first parameter value.

How to embed all parameters into a single string without breaking it up into multiple strings?

$@ works to print all texts, because it contains all parameters passed to the procedure. However, it's not a solutions to me, because I can not distinguish when the string from $2 starts or in other words, how many parts belong to $1.

Paebbels
  • 15,573
  • 13
  • 70
  • 139
  • Add a shebang and then paste your script there: http://www.shellcheck.net/ Ignore the certificate that expired today. – Cyrus Nov 24 '18 at 18:56
  • Nice checker! I see now, I need to change `@` to `*` which does not expand to single strings if contained in double quotes. – Paebbels Nov 24 '18 at 19:14
  • You should read [I'm trying to put a command in a variable, but the complex cases always fail](http://mywiki.wooledge.org/BashFAQ/050) – glenn jackman Nov 24 '18 at 23:36

1 Answers1

0

As proposed by Cyrus, I used shellcheck.net to check my Bash script.

Here is the output from the checker:

$ shellcheck myscript

Line 24:
    echo "echo \"$@\"" >&3
                 ^-- SC2145: Argument mixes string and array. Use * or separate argument.

Line 33:
    --egg=4
    ^-- SC2191: The = here is literal. To assign by index, use ( [index]=value ) with no spaces. To keep as literal, quote it.

Line 39:
    --spice=4
    ^-- SC2191: The = here is literal. To assign by index, use ( [index]=value ) with no spaces. To keep as literal, quote it.

Line 44:
echo "$Program_A -a ${Paramater_A[@]}"
                    ^-- SC2145: Argument mixes string and array. Use * or separate argument.

Line 45:
echo "$Program_B -b ${Paramater_B[@]}"
                    ^-- SC2145: Argument mixes string and array. Use * or separate argument.

Line 47:
procedure1 "$Program_A -a ${Paramater_A[@]}" "$Program_B -b ${Paramater_B[@]}"
                          ^-- SC2145: Argument mixes string and array. Use * or separate argument.
>>                                                          ^-- SC2145: Argument mixes string and array. Use * or separate argument.

Line 48:
procedure2 "$Program_A -a ${Paramater_A[@]}" "$Program_B -b ${Paramater_B[@]}"
                          ^-- SC2145: Argument mixes string and array. Use * or separate argument.
>>                                                          ^-- SC2145: Argument mixes string and array. Use * or separate argument.

Line 49:
procedure3 "$Program_A -a ${Paramater_A[@]}" "$Program_B -b ${Paramater_B[@]}"
                          ^-- SC2145: Argument mixes string and array. Use * or separate argument.
>>                                                          ^-- SC2145: Argument mixes string and array. Use * or separate argument.

It shows that the used @ needs to be changed to *. @ contained in double quotes expands to each array element contained in double quotes, whereas * expands into the string.

Paebbels
  • 15,573
  • 13
  • 70
  • 139