1

In bash, is there a better way to pass a variable as file argument than process substitution and echo -n?

v1='...'
v2='...'
comm <(echo -n "$v1") <(echo -n "$v2")

The following works for one file argument, at the cost of some readability:

comm <(echo -n "$v1") - <<<"$v2"

Maybe it is a little bit faster? Is there a better option for 2+ files? Basically, I am looking for the opposite of v1=$(<filename).

1
  • 2
    Apart from the same with printf, not really. However, it's worth checking if this data should be in variables in the first place. Storing files and large outputs in variables is a common antipattern. Commented May 11, 2019 at 22:18

2 Answers 2

3
$ v1=$(seq 1 3); v2=$(seq 2 4)

$ comm /dev/fd/3 3<<<"$v1" /dev/fd/4 4<<<"$v2"
1
                2
                3
        4

In the above 3<<<"$v1" and 4<<<"$v2" is making file descriptors 3 and 4 point to the temp files generated by the <<<s and then running comm on those file descriptors. Using awk you can see that happens:

$ awk 'BEGIN{for (i in ARGV) print i, ARGV[i]} {print FILENAME, $0}' /dev/fd/3 3<<<"$v1" /dev/fd/4 4<<<"$v2" 
0 awk
1 /dev/fd/3
2 /dev/fd/4
/dev/fd/3 1
/dev/fd/3 2
/dev/fd/3 3
/dev/fd/4 2
/dev/fd/4 3
/dev/fd/4 4

You can change the command line order of FD assignment vs usage if you find some other arrangement more readable and you can keep going, e.g.:

$ v3=$(seq 4 6); v4=$(seq 6 8)

$ paste /dev/fd/3 3<<<"$v1" /dev/fd/4 4<<<"$v2" /dev/fd/5 5<<<"$v3" /dev/fd/6 6<<<"$v4"
1       2       4       6
2       3       5       7
3       4       6       8

but you should really question why you're doing that if you do find yourself considering it as chances are there's a better approach for whatever it is you really need to do.

See https://unix.stackexchange.com/a/148153/133219 for more info.

Sign up to request clarification or add additional context in comments.

4 Comments

That's actually a clever way to do it. So it is not all that different from process substitution which is using the same FDs. I hope (and think) that this does not actually put the data on disk because that's what I wanted to avoid. Otherwise I could have used temp files anyway.
I have come across this situation a few times in the past wondering if there was a better way. Last time I had to do several computation steps (leading up to those variables) and then needed awk to work on them. It only takes files (and stdin) for input. And the echo -n stuff always felt like "useless of echo".
I'm afraid here strings like <<<, just like with << for here documents, use a temporary file. There's no way to do what you want without one AFAIK since your command is expecting to read from files.
Looks like even for a here string, bash uses a temporary file instead of piping stdin. I was under the assumption this would be more efficient because it would not hit the disk. In the end, echo -n abc | somecommand might be even more efficient than somecommand <<<'abc'.
0

I may not understand, but it looks like you're overthinking it.

awk '{print $2}' "$v1" "$v2"

If {v1} and {v2} are not filenames, but data, you can use a heredoc:

awk '{print $2}' <<EOF
$v1
$v2
EOF

Or a here-string:

awk '{print $2}' RS=: <<< "$v1:$v2"

3 Comments

v1 and v2 are strings, not filenames. Solution 2 and 3 assume that both could just be concatenated. This question is about cases when this is not possible, e.g. if the awk script would use the NR==FNR trick to do something different for the first file. Also, awk is just an example. It could also be comm which expects two file arguments.
Why would you use file slurp $(<file) in the first place, if what you want is to process files? Are you using some other utility that you only know how to use on strings? You've abstracted this problem.
As I wrote v1=$(<filename) is not what I am looking for but roughly the opposite. It has different use cases of course.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.