Issue
So, i have a horrifying oneliner, that gets a json value extracts data from it using jq and then iterates over the data with xargs. In the end it should produces some xml
legendary list-installed --json | jq '.[].title' | sed s/"\""/""/g | xargs -n1 -p -d "\n" -I {} echo '<button onclick="'$(legendary list-installed --json | jq 'map(if .title == "'{}'" then .app_name elif .title == "_" then "_" else "_" end)')'">'{}'</button>'
First of all, i didn't use the -r
flag with jq because i thought the issue might be comming from it.
The expected output should be something like this:
<button onclick=app name e.g. Coley> The Escapist 2 </button>
So far that works (except for the app name part, as thats where it begins to get weird)
Because i hardly can debug with jq inside the command substition, i wanted to test what xargs gets passed into stdin via another command substition. I changed the part between the two button elements {}
to $(echo {})
, which still works. But by accident i piped it into wc -w
, which outputs ONE if the content of the {} is actually TWO!
❯ ./test.sh
<layout>
echo 'button onclick="[' '"_",' '"_",' '"_"' ']">Ape Out</button>' ?...^C⏎
> cat test.sh
...'$(echo {})'</button>'
If i just echo the content of {} it returns this (i know that thats a useless echo, its just for consistency): When i count the words inside of my shell, and not inside of xargs
legendary list-installed --json | jq '.[].title' | head -n 1 | sed s/"\""/""/g | wc -w
it does return two.
Output of running with set -x
❯ ./test.sh
+ echo '<layout>'
<layout>
+ legendary list-installed --json
+ jq '.[].title'
+ sed 's/"//g'
++ legendary list-installed --json
++ jq 'map(if .title == "{}" then .app_name elif .title == "_" then "_" else "_" end)'
++ echo '{}'
++ tee lolsu,txt
+ xargs -n1 -p -d '\n' -I '{}' echo 'button onclick="[' '"_",' '"_",' '"_"' ']">{}</button>'
echo 'button onclick="[' '"_",' '"_",' '"_"' ']">Ape Out</button>' ?...
Seems like its not being substituted correctly... New problem is how i would make it replace the {} with the real one, inside of the substition.
TLDR: counting the value of xargs returns one, while the piped input should be two words (as i am iterating over line and not word) When running in shell it returns two (without using xargs, obv)
Solution
When you write
$(echo {} | wc -w)`
The input to the wc -w
command is the string {}
. That's one word, so the result is 1
, and that gets substituted in place of $(echo {} | wc -w)
. It's not substituting anything from xargs
there, because command substitutions are executed first and the results substituted into the command line.
So the argument that xargs
receives contains this 1
already substituted.
Answered By - Barmar