How can I use filename expansion with here strings in Bash?
Asked by
CuriousCoder42
I'm trying to understand why filename expansion doesn't work with here strings in Bash. When I use the command `cat <<< /var/cache/*`, it simply outputs `/var/cache/*`, rather than expanding to the actual filenames like it does in other contexts. The official documentation mentions that filename expansion and word splitting aren't performed with here strings, but I'm looking for ways to work around this limitation. Is there a way to make filename expansions work alongside here strings, perhaps through shell flags, patches, or any other methods? Also, is there a reason why variable expansion functions in here strings but filename expansion does not?
Answers
Before diving deeper, could you share what output youโre expecting? Knowing your end goal can really help us provide better solutions!
Reply to this answer
Honestly, it seems to be working as designed! You're trying to do `command <<< some_thing_to_expand`, but filename expansion just isn't something that works here directly. Instead, you can first expand the glob into a variable and then feed that into the here string. For example:
```
(set -- *; cat <<< $*)
```
This way, the expanded filenames are passed in a single input line, which `cat` can read as standard input. Just keep in mind that it wonโt treat them as separate arguments.
Reply to this answer
A good way to handle this is to expand the filenames into an array first. This allows more control, and you can easily convert that array into a space-separated string later if needed. The reason filename expansion doesnโt work in here strings is that it can generate multiple words on its own. The context of here strings doesn't perform word splitting, which is why you won't see filename expansion occurring either. It's similar to how certain constructs like `case` statements donโt perform filename expansion either.
Reply to this answer
The reason behind this behavior is that here strings are meant to handle input as standard input rather than arguments. Hence, features like filename expansion arenโt applied. One workaround is using command substitution. For instance:
```
cat <<< "$(echo /var/cache/*)"
```
This works because filename expansion happens in the context of `echo`, and then that output is used as standard input for `cat`. Another method is using a pipe, like:
```
echo /var/cache/* | cat
```
This accomplishes the same thing by piping the expanded output directly to `cat`.
Reply to this answer
Using filename expansions in that context can get tricky, especially with spaces in filenames! It's safer to rely on arrays to manage filenames, ensuring they are properly split and quoted. With arrays, you can loop through each filename individually before passing them to the command, avoiding issues caused by spaces or special characters.
Reply to this answer
Add your answer
Answers are reviewed before publication.
Related Discussions