I have an input file that contains only one line:
$ cat input
foo bar
I want to use this line in my script and there are 3 ways to get it that I know of:
line=$(cat input)
line=$(<input)
IFS= read -r line < input
For example, using command substitution means I spawn a subshell, whereas with read
I do not, correct? What other differences are there and is one way preferred over the others? I also noticed (with strace
) that only read
triggers the syscall openat
for some reason. How is it possible that the others don't?
$ strace ./script |& grep input
read(3, "#!/usr/bin/env bash\n\ncat > input"..., 80) = 80
read(255, "#!/usr/bin/env bash\n\ncat > input"..., 167) = 167
read(255, "\nline=$(cat input)\nline=$(<input"..., 167) = 60
read(255, "line=$(<input)\nIFS= read -r line"..., 167) = 41
read(255, "IFS= read -r line < input\n", 167) = 26
openat(AT_FDCWD, "input", O_RDONLY) = 3
There is no difference from a user point of view. These commands do the same thing. Technically the difference is in what program opens the file: the cat program or the shell that runs it.
We use the read command with -r argument to read the contents without escaping the backslash character. We read the content of each line and store that in the variable line and inside the while loop we echo with a formatted -e argument to use special characters like \n and print the contents of the line variable.
line=$(cat input)
is the POSIX way of reading the entire file. It requires a fork.
line=$(< input)
is a marginally more efficient Bashism for reading the entire file. It also forks, but doesn't have to execve.
Not mentioned but mapfile
/readarray
are significantly more efficient Bashisms for reading the entire file line-by-line into arrays. No forks.
IFS= read -r line < input
is the POSIX way of reading a single line without a subshell. No forks.
The reason why you only see the latter opening the file is simply that the others do it in a subshell, and you haven't specified -f
to trace child processes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With