10

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
codeforester
  • 34,080
  • 14
  • 96
  • 122
mickp
  • 1,559
  • 5
  • 18
  • 1
    *"that only `read` triggers the syscall openat for some reason. How is it possible that the others don't?"* -- as you already know, the first two commands read the file in a sub-shell. Make sure you ask `strace` to also trace the child processes spawn by the initial process you trace. – axiac Aug 20 '18 at 20:13

1 Answers1

17
  • 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.

that other guy
  • 109,738
  • 11
  • 156
  • 185
  • 3
    Heh. I was under the mistaken impression that `$(<... a="" all="" also="" and="" bash="" be="" but="" can="" certainly="" do="" efficient="" for="" forks.="" future="" future.="" implementation="" improved="" in="" in-process="" into="" is="" it="" just="" locking="" longer="" more="" much="" neither="" no="" not="" one="" posix="" possible="" provide="" quite="" release="" right="" said="" so="" syntax="" that="" the="" thus="" to="" using="" was="" whereas="" you=""> – Charles Duffy Aug 20 '18 at 20:02