Fish command substitution for arguments -- eval safe?
Asked Answered
C

2

-1

In fish shell, I want to be able to expand a command substitution or variable as multiple arguments to another command, e.g.:

Without substitution

ls -l -h

Should give the same result as:

ls $(echo '-l -h')

Instead the second one gives an error:

ls: invalid option -- ' '

If I instead do:

eval ls $(echo '-l -h')

It does what I want, it seems.

2 questions then:

  1. Is using eval in this way actually going to do what I want consistently?
  2. Is there some other way I should be doing this instead?

I read this question and answer, which is very similar to mine: Command substitution in fish

But the answer is not applicable in my situation.

The real world use case I have is following the instructions for gstreamer: https://gstreamer.freedesktop.org/documentation/installing/on-linux.html?gi-language=c#

Where it says to build the tutorials with:

gcc basic-tutorial-1.c -o basic-tutorial-1 `pkg-config --cflags --libs gstreamer-1.0`

Which, of course, does not work in fish (because backticks). But when converted to $() syntax, it errors with:

gcc: error: unrecognized command-line option ‘-pthread -I/usr/include/gstreamer-1.0 -I/ ....

Because it has interpreted the output of the $() block as a single string -- which makes sense and seems sensible, except that it is blocking this very reasonable (imo) use case, and I'd like to be able to do this comfortably in fish.

Thanks!

Cauldron answered 24/9, 2023 at 16:46 Comment(5)
This looks to me like a job for string split, not eval.Validity
ls $(echo '-l -h') doesn't require eval on my config!!? What's your environment?Pigment
@F.Hauri-GiveUpGitHub, note that this is a fish question, not a bash question. (The OP really shouldn't be tagging it bash; I've edited accordingly).Validity
But are fish something shell compatible? I think OP could just use fish.Pigment
@F.Hauri-GiveUpGitHub, the shell tag says it should be assumed to be POSIX if the OP tags no other shells, but it's allowable for non-POSIX shells if such a shell is tagged explicitly.Validity
J
4

This is explicitly called out in the FAQ section of fish's documentation, with pkg-config as an example:

Unlike other shells, fish splits command substitutions only on newlines, not spaces or tabs or the characters in $IFS.

However sometimes, especially with pkg-config and related tools, splitting on spaces is needed.

In these cases use string split -n " " like:

g++ example_01.cpp (pkg-config --cflags --libs gtk+-2.0 | string split -n " ")

So your command becomes:

gcc basic-tutorial-1.c -o basic-tutorial-1 $(pkg-config --cflags --libs gstreamer-1.0 | string split -n " ")

Is using eval in this way actually going to do what I want consistently?

Definitely not. If your command prints something that looks like any sort of expansion it will be executed.

So if it printed e.g. a * or a $ or a () it would run the actual expansion. In your particular case it is not impossible for the path to contain any of these characters.

Jakoba answered 24/9, 2023 at 17:5 Comment(0)
V
1
set var '-l -h'
set var_array (string split ' ' -- "$var")
ls $var_array
Validity answered 24/9, 2023 at 16:52 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.