How to use variables within CLI command to build transaction for sending a token?

I have this CLI to build a transaction that works fine.


cardano-cli transaction build-raw \
	--tx-in 816e3e5a7065516e6032570fa5b83fb74f9ed6b584b5843f72331adefb1632ac#5 --tx-in 307b3b6a6de2cca46d805b0465e50bf9a8b966a5e45bae23de975daae35b08c3#1 \
	--tx-out addr1y8xfge67hnrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0c555+1500000+"1 8654e8b350e298c80d2451beb5ed80fc9eee9f38ce6b039fb8706bc3.4c4f4253544552" \
	--tx-out addr1q8xfge6xvkrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0cc3p+0 \
	--fee 0 \
	--out-file tx.draft

I want to put the --tx-out in a variable called $txout but I get an error.

option --tx-out:
unexpected "\""
expecting white space or quantity (word64)

Here’s the $txout variable:


txout="--tx-out addr1y8xfge67hnrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0c555+1500000+\"1 8654e8b350e298c80d2451beb5ed80fc9eee9f38ce6b039fb8706bc3.4c4f4253544552\""

And here’s the new build:


cardano-cli transaction build-raw \
	--tx-in 816e3e5a7065516e6032570fa5b83fb74f9ed6b584b5843f72331adefb1632ac#5 --tx-in 307b3b6a6de2cca46d805b0465e50bf9a8b966a5e45bae23de975daae35b08c3#1 \
	$txout \
	--tx-out addr1q8xfge6xvkrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0cc3p+0 \
	--fee 0 \
	--out-file tx.draft

So how do you put the --tx-out part in a variable including the double quotes? I tried to escape the double quotes with " but it did not work. Any help is appreciated.

Sorry, now I’m awake. Unfortunately, I cannot test that here, because the cardano-cli bundled with daedalus that I have here already chokes at the '+'s. Did they change that in recent versions?

option --tx-out:
unexpected "+"
invalid address
...
$ cardano-cli --version
cardano-cli 1.30.1 - linux-x86_64 - ghc-8.10
git rev 0fb43f4e3da8b225f4f86557aed90a183981a64f

Anyway, the effect of the double quotes in your version without variable is that the shell gives the whole string to cardano-cli as one argument and does not break it in two at the space. But cardano-cli does not see the quotes and obviously cannot handle them. It should be equivalent to:

cardano-cli transaction build-raw \
	--tx-in 816e3e5a7065516e6032570fa5b83fb74f9ed6b584b5843f72331adefb1632ac#5 --tx-in 307b3b6a6de2cca46d805b0465e50bf9a8b966a5e45bae23de975daae35b08c3#1 \
	--tx-out "addr1y8xfge67hnrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0c555+1500000+1 8654e8b350e298c80d2451beb5ed80fc9eee9f38ce6b039fb8706bc3.4c4f4253544552" \
	--tx-out addr1q8xfge6xvkrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0cc3p+0 \
	--fee 0 \
	--out-file tx.draft

But in the version with variables, they are in there and also given to cardano-cli. So, it chokes on them.

Try :

txin1="816e3e5a7065516e6032570fa5b83fb74f9ed6b584b5843f72331adefb1632ac#5"
txin2="307b3b6a6de2cca46d805b0465e50bf9a8b966a5e45bae23de975daae35b08c3#1"
txout1="addr1y8xfge67hnrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0c555+1500000+1 8654e8b350e298c80d2451beb5ed80fc9eee9f38ce6b039fb8706bc3.4c4f4253544552"
txout2="addr1q8xfge6xvkrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0cc3p+0"

cardano-cli transaction build-raw \
    --tx-in "$txin1" --tx-in "$txin2" \
    --tx-out "$txout1" --txout "$txout2" \
    --fee 0 \
    --out-file tx.draft
1 Like

For the details: How the shell handles arguments and quotes:

With a small test script, we can test what happens, when we quote arguments and put them in variables in different ways:

$ cat test.sh
#!/bin/sh
for (( i=1; i <= "$#"; i++ )); do
    echo "Argument ${i}: ${!i}"
done

Without quotes:

$ ./test.sh --test Hello World
Argument 1: --test
Argument 2: Hello
Argument 3: World

With quotes as in your working example:

$ ./test.sh --test Hello" World"
Argument 1: --test
Argument 2: Hello World

Or equivalently (and arguably better readable):

$ ./test.sh --test "Hello World"
Argument 1: --test
Argument 2: Hello World

With the option name in the variable:

$ test="--test Hello World"
$ ./test.sh $test
Argument 1: --test
Argument 2: Hello
Argument 3: World
$ ./test.sh "$test"
Argument 1: --test Hello World

With quotes in the variable:

$ test="--test \"Hello World\""
$ ./test.sh $test
Argument 1: --test
Argument 2: "Hello
Argument 3: World"
$ ./test.sh "$test"
Argument 1: --test "Hello World"

This does not work out either way. We need to separate the option name and only put the argument in the variable:

$ test="Hello World"
$ ./test.sh --test $test
Argument 1: --test
Argument 2: Hello
Argument 3: World
$ ./test.sh --test "$test"
Argument 1: --test
Argument 2: Hello World

The last one is the one we want: Only the variable part without the option name (–tx-out in our case) in the variable and its usage is also quoted, so that it gets given to the script in one piece.

3 Likes

Thanks to @HeptaSean for his detailed explanation!

Putting the option name inside the variable is really what I’m trying to do because I find it easier to build the transaction with multiple --tx-out but as you mentioned above, it does not work. Is this just for the --tx-out part? I asked this because putting the option name --tx-in inside a variable works fine.

This one works fine:

TX_INS="--tx-in 816e3e5a7065516e6032570fa5b83fb74f9ed6b584b5843f72331adefb1632ac#5 --tx-in 307b3b6a6de2cca46d805b0465e50bf9a8b966a5e45bae23de975daae35b08c3#1"
txout1="addr1y8xfge67hnrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0c555+1500000+1 8654e8b350e298c80d2451beb5ed80fc9eee9f38ce6b039fb8706bc3.4c4f4253544552"
txout2="addr1q8xfge6xvkrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0cc3p+0"

cardano-cli transaction build-raw \
    $TX_INS \
    --tx-out "$txout1" --txout "$txout2" \
    --fee 0 \
    --out-file tx.draft

Update: Let me just paste my CLI version here:

tinkerboy@ubuntu:~$ cardano-cli --version
cardano-cli 1.31.0 - linux-x86_64 - ghc-8.10
git rev b91eb99f40f8ea88a3b6d9fb130667121ecbe522

1 Like

Okay, I learned something new today. Normally, I use Python for stuff like that, not bash, but it is possible with bash:

txins=()
txins+=("--tx-in" "816e3e5a7065516e6032570fa5b83fb74f9ed6b584b5843f72331adefb1632ac#5")
txins+=("--tx-in" "307b3b6a6de2cca46d805b0465e50bf9a8b966a5e45bae23de975daae35b08c3#1")
txouts=()
txouts+=("--tx-out" "addr1y8xfge67hnrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0c555+1500000+1 8654e8b350e298c80d2451beb5ed80fc9eee9f38ce6b039fb8706bc3.4c4f4253544552")
txouts+=("--tx-out" "addr1q8xfge6xvkrk6gu0sf6dck59l954jk673mkmt36l0ffalcyc82nq77cazuaf65xpgqhdp90cmcajr8nuyztgfqg2dg7qh0cc3p+0")

cardano-cli transaction build-raw \
    "${txins[@]}" "{txouts[@]}" \
    --fee 0 \
    --out-file tx.draft

We use an array of strings instead of just one string here. The “[@]” selects all elements of such an array and the outer quotes make that all the elements in the array are bound together (just like when surrounding them with quotes when giving them as arguments directly) before giving them to cardano-cli.

Why start with txins=()?

You wouldn’t need to start with an empty array and could just do

txins=("--tx-in" "816e3e5a7065516e6032570fa5b83fb74f9ed6b584b5843f72331adefb1632ac#5")
txins+=("--tx-in" "307b3b6a6de2cca46d805b0465e50bf9a8b966a5e45bae23de975daae35b08c3#1")

or even

txins=("--tx-in" "816e3e5a7065516e6032570fa5b83fb74f9ed6b584b5843f72331adefb1632ac#5" "--tx-in" "307b3b6a6de2cca46d805b0465e50bf9a8b966a5e45bae23de975daae35b08c3#1")

but I felt it’s somehow nicer code to add the different inputs and outputs piece by piece with similar commands.

Hope that makes sense to you?

2 Likes

Thank you very much! This is the solution I’m looking for. :slight_smile: I have tried and tested it and it works great!