MacOS – How to use zsh to pipe results from one command to another (while in a loop)

command linemacosterminalzsh

macOS 10.14.6
zsh 5.8
jq 1.6

I have a situation where I have a bunch of .vital files, which are JSON files in disguise. I want to extract one piece of information from each file, and I have worked out that after installing jq using brew install jq, I can run, for example…

jq '.author' Analog_Bass__Lead.vital;

This gives me…

"maniclout"

which is the correct author for that item.

What I would like to do is to run this command over all my .vital files, about 30 of them, in a for loop.

I can list the files okay using…

for f in $(ls *.vital);
do
  echo $f
done;

The problem comes when I try to construct a loop that would give the following…

Analog_Bass__Lead.vital "maniclout"
Blackhole_Dimension.vital "Cobranix"

and so on…

This my latest attempt (please, don't laugh!)…

for f in $(ls *.vital);
do
  echo $f;
  echo -n $f | jq ‘.author’
done;

As you can see, I'm trying to print the filename, followed by, on the same line, hence the -n, and I'm trying to pipe the filename into the jq command.

The results are fairly disastrous!

ANALOG_PAD_-_6.vital
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
‘.author’
jq: 1 compile error
Analog_Bass__Lead.vital
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
‘.author’
jq: 1 compile error
Atomosphere_Lead.vital
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
‘.author’
jq: 1 compile error

Can anyone see what I am doing wrong?

Best Answer

Do not parse/interpret the output of ls, too many things can go wrong. A simple way to accomplish your goal would be

for f in *.vital; do
    echo -n "$f: "
    jq '.author' "$f"
done

which might still fail if there are directories matching the pattern for instance. You can overcome this by using

for f in *.vital; do
    [[ -f "$f" ]] || continue
    echo -n "$f: "
    jq '.author' "$f"
done

You can also go the full way and run

find . -maxdepth 1 -type f -name '*.vital' \
     -exec sh -c 'echo -n "$1"; jq ".author" "$1"' _ {} \;

(see http://mywiki.wooledge.org/UsingFind#Complex_actions for how this works)