Understanding Bash's Read-a-File Command Substitution
I am trying to understand how exactly Bash treats the following line:
$(< "$FILE")
According to the Bash man page, this is equivalent to:
$(cat "$FILE")
and I can follow the line of reasoning for this second line. Bash performs variable expansion on $FILE
, enters command substitution, passes the value of $FILE
to cat
, cat outputs the contents of $FILE
to standard output, command substitution finishes by replacing the entire line with the standard output resulting from the command inside, and Bash attempts to execute it like a simple command.
However, for the first line I mentioned above, I understand it as: Bash performs variable substitution on $FILE
, Bash opens $FILE
for reading on standard input, somehow standard input is copied to standard output, command substitution finishes, and Bash attempts to execute the resulting standard output.
Can someone please explain to me how the contents of $FILE
goes from stdin to stdout?
bash shell io-redirection command-substitution
add a comment |
I am trying to understand how exactly Bash treats the following line:
$(< "$FILE")
According to the Bash man page, this is equivalent to:
$(cat "$FILE")
and I can follow the line of reasoning for this second line. Bash performs variable expansion on $FILE
, enters command substitution, passes the value of $FILE
to cat
, cat outputs the contents of $FILE
to standard output, command substitution finishes by replacing the entire line with the standard output resulting from the command inside, and Bash attempts to execute it like a simple command.
However, for the first line I mentioned above, I understand it as: Bash performs variable substitution on $FILE
, Bash opens $FILE
for reading on standard input, somehow standard input is copied to standard output, command substitution finishes, and Bash attempts to execute the resulting standard output.
Can someone please explain to me how the contents of $FILE
goes from stdin to stdout?
bash shell io-redirection command-substitution
add a comment |
I am trying to understand how exactly Bash treats the following line:
$(< "$FILE")
According to the Bash man page, this is equivalent to:
$(cat "$FILE")
and I can follow the line of reasoning for this second line. Bash performs variable expansion on $FILE
, enters command substitution, passes the value of $FILE
to cat
, cat outputs the contents of $FILE
to standard output, command substitution finishes by replacing the entire line with the standard output resulting from the command inside, and Bash attempts to execute it like a simple command.
However, for the first line I mentioned above, I understand it as: Bash performs variable substitution on $FILE
, Bash opens $FILE
for reading on standard input, somehow standard input is copied to standard output, command substitution finishes, and Bash attempts to execute the resulting standard output.
Can someone please explain to me how the contents of $FILE
goes from stdin to stdout?
bash shell io-redirection command-substitution
I am trying to understand how exactly Bash treats the following line:
$(< "$FILE")
According to the Bash man page, this is equivalent to:
$(cat "$FILE")
and I can follow the line of reasoning for this second line. Bash performs variable expansion on $FILE
, enters command substitution, passes the value of $FILE
to cat
, cat outputs the contents of $FILE
to standard output, command substitution finishes by replacing the entire line with the standard output resulting from the command inside, and Bash attempts to execute it like a simple command.
However, for the first line I mentioned above, I understand it as: Bash performs variable substitution on $FILE
, Bash opens $FILE
for reading on standard input, somehow standard input is copied to standard output, command substitution finishes, and Bash attempts to execute the resulting standard output.
Can someone please explain to me how the contents of $FILE
goes from stdin to stdout?
bash shell io-redirection command-substitution
bash shell io-redirection command-substitution
edited Sep 3 '17 at 5:43
Scott
6,94152750
6,94152750
asked Mar 12 '15 at 14:52
Stanley YuStanley Yu
1954
1954
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
The <
isn't directly an aspect of bash command substitution. It is a redirection operator (like a pipe), which some shells allow without a command (POSIX does not specify this behavior).
Perhaps it would be more clear with more spaces:
echo $( < $FILE )
this is effectively* the same as the more POSIX-safe
echo $( cat $FILE )
... which is also effectively*
echo $( cat < $FILE )
Let's start with that last version. This runs cat
with no arguments, which means it will read from standard input. $FILE
is redirected into standard input due to the <
, so cat
puts its contents are put into standard output. The $(command)
subsitution then pushes cat
's output into arguments for echo
.
In bash
(but not in the POSIX standard), you can use <
without a command. bash
(and zsh
and ksh
but not dash
) will interpret that as if cat <
, though without invoking a new subprocess. As this is native to the shell, it is faster than literally running the external command cat
. *This is why I say "effectively the same as."
So in the last paragraph when you say "bash
will interpret that ascat filename
", do you mean this behavior is specific to command substitution? Because if I run< filename
by itself, bash does not cat it out. It will output nothing and return me back to a prompt.
– Stanley Yu
Mar 12 '15 at 20:06
A command is still needed. @cuonglm altered my original text fromcat < filename
tocat filename
which I oppose and may revert.
– Adam Katz
Mar 12 '15 at 20:11
1
A pipe is a type of file. The shell operator|
creates a pipe between two subprocesses (or, with some shells, from a subprocess to the shell's standard input). The shell operator$(…)
creates a pipe from a subprocess to the shell itself (not to its standard input). The shell operator<
does not involve a pipe, it only opens a file and moves the file descriptor to standard input.
– Gilles
Mar 12 '15 at 23:15
2
< file
is not the same ascat < file
(except inzsh
where it's like$READNULLCMD < file
).< file
is perfectly POSIX and just opensfile
for reading and then does nothing (sofile
is close straight away). It's$(< file)
or`< file`
that is a special operator ofksh
,zsh
andbash
(and the behaviour is left unspecified in POSIX). See my answer for details.
– Stéphane Chazelas
Aug 23 '17 at 15:41
1
To put @StéphaneChazelas’s comment in another light: to a first approximation,$(cmd1) $(cmd2)
will typically be the same as$(cmd1; cmd2)
. But look at the case wherecmd2
is< file
. If we say$(cmd1; < file)
, the file is not read, but, with$(cmd1) $(< file)
, it is. So it is incorrect to say that$(< file)
is just an ordinary case of$(command)
with a command of< file
.$(< …)
is a special case of command substitution, and not a normal usage of redirection.
– Scott
Sep 3 '17 at 5:44
|
show 13 more comments
$(<file)
(also works with `<file`
) is a special operator of the Korn shell copied by zsh
and bash
. It does look a lot like command substitution but it's not really.
In POSIX shells, a simple command is:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
All parts are optional, you can have redirections only, command only, assignment only or combinations.
If there are redirections but no command, the redirections are performed (so a > file
would open and truncate file
), but then nothing happens. So
< file
Opens file
for reading, but then nothing happens as there's no command. So the file
is then closed and that's it. If $(< file)
was a simple command substitution, then it would expand to nothing.
In the POSIX specification, in $(script)
, if script
consists only of redirections, that produces unspecified results. That's to allow that special behaviour of the Korn shell.
In ksh (here tested with ksh93u+
), if the script consists of one and only one simple command (though comments are allowed before and after) that consists only of redirections (no command, no assignment) and if the first redirection is a stdin (fd 0) input only (<
, <<
or <<<
) redirection, so:
$(< file)
$(0< file)
$(<&3)
(also$(0>&3)
actually as that's in effect the same operator)$(< file > foo 2> $(whatever))
but not:
$(> foo < file)
- nor
$(0<> file)
- nor
$(< file; sleep 1)
- nor
$(< file; < file2)
then
- all but the first redirection are ignored (they are parsed away)
- and it expands to the content of the file/heredoc/herestring (or whatever can be read from the file descriptor if using things like
<&3
) minus the trailing newline characters.
as if using $(cat < file)
except that
- the reading is done internally by the shell and not by
cat
- no pipe nor extra process is involved
- as a consequence of the above, since the code inside is not run in a subshell, any modification remain thereafter (as in
$(<${file=foo.txt})
or$(<file$((++n)))
) - read errors (though not errors while opening files or duplicating file descriptors) are silently ignored.
In zsh
, it's the same except that that special behaviour is only triggered when there's only one file input redirection (<file
or 0< file
, no <&3
, <<<here
, < a < b
...)
However, except when emulating other shells, in:
< file
<&3
<<< here...
that is when there are only input redirections without commands, outside of command substitution, zsh
runs the $READNULLCMD
(a pager by default), and when there are both input and output redirections, the $NULLCMD
(cat
by default), so even if $(<&3)
is not recognized as that special operator, it will still work like in ksh
though by invoking a pager to do it (that pager acting like cat
since its stdout will be a pipe).
However while ksh
's $(< a < b)
would expand to the content of a
, in zsh
, it expands to the content of a
and b
(or just b
if the multios
option is disabled), $(< a > b)
would copy a
to b
and expand to nothing, etc.
bash
has a similar operator but with a few differences:
comments are allowed before but not after:
echo "$(
# getting the content of file
< file)"
works but:
echo "$(< file
# getting the content of file
)"
expands to nothing.
like in
zsh
, only one file stdin redirection, though there's no fall back to a$READNULLCMD
, so$(<&3)
,$(< a < b)
do perform the redirections but expand to nothing.- for some reason, while
bash
does not invokecat
, it still forks a process that feeds the content of the file through a pipe making it much less of an optimisation than in other shells. It's in effect like a$(cat < file)
wherecat
would be a builtincat
. - as a consequence of the above, any change made within are lost afterwards (in the
$(<${file=foo.txt})
, mentioned above for instance, that$file
assignment is lost afterwards).
In bash
, IFS= read -rd '' var < file
(also works in zsh
) is a more effective way to read the content of a text file into a variable. It also has the benefit of preserving the trailing newline characters. See also $mapfile[file]
in zsh
(in the zsh/mapfile
module and only for regular files) which also works with binary files.
Note that the pdksh-based variants of ksh
have a few variations compared to ksh93. Of interest, in mksh
(one of those pdksh-derived shells), in
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
is optimised in that the content of the here document (without the trailing characters) is expanded without a temporary file or pipe being used as is otherwise the case for here documents, which makes it an effective multi-line quoting syntax.
To be portable to all versions of ksh
, zsh
and bash
, best is to limit to only $(<file)
avoiding comments and bearing in mind that modifications to variables made within may or may not be preserved.
Is it correct that$(<)
is an operator on filenames? Is<
in$(<)
a redirection operator, or not an operator on its own, and must be part of the entire operator$(<)
?
– Tim
Aug 23 '17 at 21:32
@Tim, it doesn't matter much how you want to call them.$(<file)
is meant to expand to the content offile
in a similar way as$(cat < file)
would. How it's done varies from shell to shell which is described at length in the answer. If you like, you can say that it's a special operator that is triggered when what looks like a command substitution (syntactically) contains what looks like a single stdin redirection (syntactically), but again with caveats and variations depending on the shell as listed here.
– Stéphane Chazelas
Aug 24 '17 at 8:21
@StéphaneChazelas: Fascinating, as usual; I’ve bookmarked this. So,n<&m
andn>&m
do the same thing? I didn’t know that, but I guess it’s not too surprising.
– Scott
Sep 3 '17 at 5:45
@Scott, yes, they both do adup(m, n)
. I can see some evidence of ksh86 using stdio and somefdopen(fd, "r" or "w")
, so it might have mattered then. But using stdio in a shell makes little sense, so I don't expect you'll find any modern shell where that will make a difference. One difference is that>&n
isdup(n, 1)
(short for1>&n
), while<&n
isdup(n, 0)
(short for0<&n
).
– Stéphane Chazelas
Sep 3 '17 at 9:08
Right. Except, of course, the two-argument form of the file descriptor duplication call is calleddup2()
;dup()
takes only one argument and, likeopen()
, uses the lowest available file descriptor. (Today I learned that there is adup3()
function.)
– Scott
Sep 3 '17 at 15:52
|
show 3 more comments
Because bash
does it internally for you, expanded the filename and cats the file to standard output, like if you were to do $(cat < filename)
. It's a bash feature, maybe you need to look into the bash
source code to know exactly how it works.
Here the the function to handle this feature (From bash
source code, file builtins/evalstring.c
):
/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */
static int
cat_file (r)
REDIRECT *r;
{
char *fn;
int fd, rval;
if (r->instruction != r_input_direction)
return -1;
/* Get the filename. */
if (posixly_correct && !interactive_shell)
disallow_filename_globbing++;
fn = redirection_expand (r->redirectee.filename);
if (posixly_correct && !interactive_shell)
disallow_filename_globbing--;
if (fn == 0)
{
redirection_error (r, AMBIGUOUS_REDIRECT);
return -1;
}
fd = open(fn, O_RDONLY);
if (fd < 0)
{
file_error (fn);
free (fn);
return -1;
}
rval = zcatfd (fd, 1, fn);
free (fn);
close (fd);
return (rval);
}
A note that $(<filename)
is not exactly equivalent to $(cat filename)
; the latter will fail if the filename starts with a dash -
.
$(<filename)
was originally from ksh
, and was added to bash
from Bash-2.02
.
1
cat filename
will fail if the filename starts with a dash because cat accepts options. You can work around that on most modern systems withcat -- filename
.
– Adam Katz
Jul 6 '17 at 1:20
add a comment |
Think of command substitution as running a command as usual and dumping the output at the point where you are running the command.
The output of commands can be used as arguments to another command, to
set a variable, and even for generating the argument list in a for
loop.
foo=$(echo "bar")
will set value of the variable $foo
to bar
; the output of the command echo bar
.
Command Substitution
1
I believe that it’s fairly clear from the question that the OP understands the basics of command substitution; the question is about the special case of$(< file)
, and he doesn't need a tutorial on the general case. If you are saying that$(< file)
is just an ordinary case of$(command)
with a command of< file
, then you are saying the same thing Adam Katz is saying, and you are both wrong.
– Scott
Sep 3 '17 at 5:44
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f189749%2funderstanding-bashs-read-a-file-command-substitution%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
The <
isn't directly an aspect of bash command substitution. It is a redirection operator (like a pipe), which some shells allow without a command (POSIX does not specify this behavior).
Perhaps it would be more clear with more spaces:
echo $( < $FILE )
this is effectively* the same as the more POSIX-safe
echo $( cat $FILE )
... which is also effectively*
echo $( cat < $FILE )
Let's start with that last version. This runs cat
with no arguments, which means it will read from standard input. $FILE
is redirected into standard input due to the <
, so cat
puts its contents are put into standard output. The $(command)
subsitution then pushes cat
's output into arguments for echo
.
In bash
(but not in the POSIX standard), you can use <
without a command. bash
(and zsh
and ksh
but not dash
) will interpret that as if cat <
, though without invoking a new subprocess. As this is native to the shell, it is faster than literally running the external command cat
. *This is why I say "effectively the same as."
So in the last paragraph when you say "bash
will interpret that ascat filename
", do you mean this behavior is specific to command substitution? Because if I run< filename
by itself, bash does not cat it out. It will output nothing and return me back to a prompt.
– Stanley Yu
Mar 12 '15 at 20:06
A command is still needed. @cuonglm altered my original text fromcat < filename
tocat filename
which I oppose and may revert.
– Adam Katz
Mar 12 '15 at 20:11
1
A pipe is a type of file. The shell operator|
creates a pipe between two subprocesses (or, with some shells, from a subprocess to the shell's standard input). The shell operator$(…)
creates a pipe from a subprocess to the shell itself (not to its standard input). The shell operator<
does not involve a pipe, it only opens a file and moves the file descriptor to standard input.
– Gilles
Mar 12 '15 at 23:15
2
< file
is not the same ascat < file
(except inzsh
where it's like$READNULLCMD < file
).< file
is perfectly POSIX and just opensfile
for reading and then does nothing (sofile
is close straight away). It's$(< file)
or`< file`
that is a special operator ofksh
,zsh
andbash
(and the behaviour is left unspecified in POSIX). See my answer for details.
– Stéphane Chazelas
Aug 23 '17 at 15:41
1
To put @StéphaneChazelas’s comment in another light: to a first approximation,$(cmd1) $(cmd2)
will typically be the same as$(cmd1; cmd2)
. But look at the case wherecmd2
is< file
. If we say$(cmd1; < file)
, the file is not read, but, with$(cmd1) $(< file)
, it is. So it is incorrect to say that$(< file)
is just an ordinary case of$(command)
with a command of< file
.$(< …)
is a special case of command substitution, and not a normal usage of redirection.
– Scott
Sep 3 '17 at 5:44
|
show 13 more comments
The <
isn't directly an aspect of bash command substitution. It is a redirection operator (like a pipe), which some shells allow without a command (POSIX does not specify this behavior).
Perhaps it would be more clear with more spaces:
echo $( < $FILE )
this is effectively* the same as the more POSIX-safe
echo $( cat $FILE )
... which is also effectively*
echo $( cat < $FILE )
Let's start with that last version. This runs cat
with no arguments, which means it will read from standard input. $FILE
is redirected into standard input due to the <
, so cat
puts its contents are put into standard output. The $(command)
subsitution then pushes cat
's output into arguments for echo
.
In bash
(but not in the POSIX standard), you can use <
without a command. bash
(and zsh
and ksh
but not dash
) will interpret that as if cat <
, though without invoking a new subprocess. As this is native to the shell, it is faster than literally running the external command cat
. *This is why I say "effectively the same as."
So in the last paragraph when you say "bash
will interpret that ascat filename
", do you mean this behavior is specific to command substitution? Because if I run< filename
by itself, bash does not cat it out. It will output nothing and return me back to a prompt.
– Stanley Yu
Mar 12 '15 at 20:06
A command is still needed. @cuonglm altered my original text fromcat < filename
tocat filename
which I oppose and may revert.
– Adam Katz
Mar 12 '15 at 20:11
1
A pipe is a type of file. The shell operator|
creates a pipe between two subprocesses (or, with some shells, from a subprocess to the shell's standard input). The shell operator$(…)
creates a pipe from a subprocess to the shell itself (not to its standard input). The shell operator<
does not involve a pipe, it only opens a file and moves the file descriptor to standard input.
– Gilles
Mar 12 '15 at 23:15
2
< file
is not the same ascat < file
(except inzsh
where it's like$READNULLCMD < file
).< file
is perfectly POSIX and just opensfile
for reading and then does nothing (sofile
is close straight away). It's$(< file)
or`< file`
that is a special operator ofksh
,zsh
andbash
(and the behaviour is left unspecified in POSIX). See my answer for details.
– Stéphane Chazelas
Aug 23 '17 at 15:41
1
To put @StéphaneChazelas’s comment in another light: to a first approximation,$(cmd1) $(cmd2)
will typically be the same as$(cmd1; cmd2)
. But look at the case wherecmd2
is< file
. If we say$(cmd1; < file)
, the file is not read, but, with$(cmd1) $(< file)
, it is. So it is incorrect to say that$(< file)
is just an ordinary case of$(command)
with a command of< file
.$(< …)
is a special case of command substitution, and not a normal usage of redirection.
– Scott
Sep 3 '17 at 5:44
|
show 13 more comments
The <
isn't directly an aspect of bash command substitution. It is a redirection operator (like a pipe), which some shells allow without a command (POSIX does not specify this behavior).
Perhaps it would be more clear with more spaces:
echo $( < $FILE )
this is effectively* the same as the more POSIX-safe
echo $( cat $FILE )
... which is also effectively*
echo $( cat < $FILE )
Let's start with that last version. This runs cat
with no arguments, which means it will read from standard input. $FILE
is redirected into standard input due to the <
, so cat
puts its contents are put into standard output. The $(command)
subsitution then pushes cat
's output into arguments for echo
.
In bash
(but not in the POSIX standard), you can use <
without a command. bash
(and zsh
and ksh
but not dash
) will interpret that as if cat <
, though without invoking a new subprocess. As this is native to the shell, it is faster than literally running the external command cat
. *This is why I say "effectively the same as."
The <
isn't directly an aspect of bash command substitution. It is a redirection operator (like a pipe), which some shells allow without a command (POSIX does not specify this behavior).
Perhaps it would be more clear with more spaces:
echo $( < $FILE )
this is effectively* the same as the more POSIX-safe
echo $( cat $FILE )
... which is also effectively*
echo $( cat < $FILE )
Let's start with that last version. This runs cat
with no arguments, which means it will read from standard input. $FILE
is redirected into standard input due to the <
, so cat
puts its contents are put into standard output. The $(command)
subsitution then pushes cat
's output into arguments for echo
.
In bash
(but not in the POSIX standard), you can use <
without a command. bash
(and zsh
and ksh
but not dash
) will interpret that as if cat <
, though without invoking a new subprocess. As this is native to the shell, it is faster than literally running the external command cat
. *This is why I say "effectively the same as."
edited Aug 25 '17 at 15:04
answered Mar 12 '15 at 18:36
Adam KatzAdam Katz
2,2401221
2,2401221
So in the last paragraph when you say "bash
will interpret that ascat filename
", do you mean this behavior is specific to command substitution? Because if I run< filename
by itself, bash does not cat it out. It will output nothing and return me back to a prompt.
– Stanley Yu
Mar 12 '15 at 20:06
A command is still needed. @cuonglm altered my original text fromcat < filename
tocat filename
which I oppose and may revert.
– Adam Katz
Mar 12 '15 at 20:11
1
A pipe is a type of file. The shell operator|
creates a pipe between two subprocesses (or, with some shells, from a subprocess to the shell's standard input). The shell operator$(…)
creates a pipe from a subprocess to the shell itself (not to its standard input). The shell operator<
does not involve a pipe, it only opens a file and moves the file descriptor to standard input.
– Gilles
Mar 12 '15 at 23:15
2
< file
is not the same ascat < file
(except inzsh
where it's like$READNULLCMD < file
).< file
is perfectly POSIX and just opensfile
for reading and then does nothing (sofile
is close straight away). It's$(< file)
or`< file`
that is a special operator ofksh
,zsh
andbash
(and the behaviour is left unspecified in POSIX). See my answer for details.
– Stéphane Chazelas
Aug 23 '17 at 15:41
1
To put @StéphaneChazelas’s comment in another light: to a first approximation,$(cmd1) $(cmd2)
will typically be the same as$(cmd1; cmd2)
. But look at the case wherecmd2
is< file
. If we say$(cmd1; < file)
, the file is not read, but, with$(cmd1) $(< file)
, it is. So it is incorrect to say that$(< file)
is just an ordinary case of$(command)
with a command of< file
.$(< …)
is a special case of command substitution, and not a normal usage of redirection.
– Scott
Sep 3 '17 at 5:44
|
show 13 more comments
So in the last paragraph when you say "bash
will interpret that ascat filename
", do you mean this behavior is specific to command substitution? Because if I run< filename
by itself, bash does not cat it out. It will output nothing and return me back to a prompt.
– Stanley Yu
Mar 12 '15 at 20:06
A command is still needed. @cuonglm altered my original text fromcat < filename
tocat filename
which I oppose and may revert.
– Adam Katz
Mar 12 '15 at 20:11
1
A pipe is a type of file. The shell operator|
creates a pipe between two subprocesses (or, with some shells, from a subprocess to the shell's standard input). The shell operator$(…)
creates a pipe from a subprocess to the shell itself (not to its standard input). The shell operator<
does not involve a pipe, it only opens a file and moves the file descriptor to standard input.
– Gilles
Mar 12 '15 at 23:15
2
< file
is not the same ascat < file
(except inzsh
where it's like$READNULLCMD < file
).< file
is perfectly POSIX and just opensfile
for reading and then does nothing (sofile
is close straight away). It's$(< file)
or`< file`
that is a special operator ofksh
,zsh
andbash
(and the behaviour is left unspecified in POSIX). See my answer for details.
– Stéphane Chazelas
Aug 23 '17 at 15:41
1
To put @StéphaneChazelas’s comment in another light: to a first approximation,$(cmd1) $(cmd2)
will typically be the same as$(cmd1; cmd2)
. But look at the case wherecmd2
is< file
. If we say$(cmd1; < file)
, the file is not read, but, with$(cmd1) $(< file)
, it is. So it is incorrect to say that$(< file)
is just an ordinary case of$(command)
with a command of< file
.$(< …)
is a special case of command substitution, and not a normal usage of redirection.
– Scott
Sep 3 '17 at 5:44
So in the last paragraph when you say "
bash
will interpret that as cat filename
", do you mean this behavior is specific to command substitution? Because if I run < filename
by itself, bash does not cat it out. It will output nothing and return me back to a prompt.– Stanley Yu
Mar 12 '15 at 20:06
So in the last paragraph when you say "
bash
will interpret that as cat filename
", do you mean this behavior is specific to command substitution? Because if I run < filename
by itself, bash does not cat it out. It will output nothing and return me back to a prompt.– Stanley Yu
Mar 12 '15 at 20:06
A command is still needed. @cuonglm altered my original text from
cat < filename
to cat filename
which I oppose and may revert.– Adam Katz
Mar 12 '15 at 20:11
A command is still needed. @cuonglm altered my original text from
cat < filename
to cat filename
which I oppose and may revert.– Adam Katz
Mar 12 '15 at 20:11
1
1
A pipe is a type of file. The shell operator
|
creates a pipe between two subprocesses (or, with some shells, from a subprocess to the shell's standard input). The shell operator $(…)
creates a pipe from a subprocess to the shell itself (not to its standard input). The shell operator <
does not involve a pipe, it only opens a file and moves the file descriptor to standard input.– Gilles
Mar 12 '15 at 23:15
A pipe is a type of file. The shell operator
|
creates a pipe between two subprocesses (or, with some shells, from a subprocess to the shell's standard input). The shell operator $(…)
creates a pipe from a subprocess to the shell itself (not to its standard input). The shell operator <
does not involve a pipe, it only opens a file and moves the file descriptor to standard input.– Gilles
Mar 12 '15 at 23:15
2
2
< file
is not the same as cat < file
(except in zsh
where it's like $READNULLCMD < file
). < file
is perfectly POSIX and just opens file
for reading and then does nothing (so file
is close straight away). It's $(< file)
or `< file`
that is a special operator of ksh
, zsh
and bash
(and the behaviour is left unspecified in POSIX). See my answer for details.– Stéphane Chazelas
Aug 23 '17 at 15:41
< file
is not the same as cat < file
(except in zsh
where it's like $READNULLCMD < file
). < file
is perfectly POSIX and just opens file
for reading and then does nothing (so file
is close straight away). It's $(< file)
or `< file`
that is a special operator of ksh
, zsh
and bash
(and the behaviour is left unspecified in POSIX). See my answer for details.– Stéphane Chazelas
Aug 23 '17 at 15:41
1
1
To put @StéphaneChazelas’s comment in another light: to a first approximation,
$(cmd1) $(cmd2)
will typically be the same as $(cmd1; cmd2)
. But look at the case where cmd2
is < file
. If we say $(cmd1; < file)
, the file is not read, but, with $(cmd1) $(< file)
, it is. So it is incorrect to say that $(< file)
is just an ordinary case of $(command)
with a command of < file
. $(< …)
is a special case of command substitution, and not a normal usage of redirection.– Scott
Sep 3 '17 at 5:44
To put @StéphaneChazelas’s comment in another light: to a first approximation,
$(cmd1) $(cmd2)
will typically be the same as $(cmd1; cmd2)
. But look at the case where cmd2
is < file
. If we say $(cmd1; < file)
, the file is not read, but, with $(cmd1) $(< file)
, it is. So it is incorrect to say that $(< file)
is just an ordinary case of $(command)
with a command of < file
. $(< …)
is a special case of command substitution, and not a normal usage of redirection.– Scott
Sep 3 '17 at 5:44
|
show 13 more comments
$(<file)
(also works with `<file`
) is a special operator of the Korn shell copied by zsh
and bash
. It does look a lot like command substitution but it's not really.
In POSIX shells, a simple command is:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
All parts are optional, you can have redirections only, command only, assignment only or combinations.
If there are redirections but no command, the redirections are performed (so a > file
would open and truncate file
), but then nothing happens. So
< file
Opens file
for reading, but then nothing happens as there's no command. So the file
is then closed and that's it. If $(< file)
was a simple command substitution, then it would expand to nothing.
In the POSIX specification, in $(script)
, if script
consists only of redirections, that produces unspecified results. That's to allow that special behaviour of the Korn shell.
In ksh (here tested with ksh93u+
), if the script consists of one and only one simple command (though comments are allowed before and after) that consists only of redirections (no command, no assignment) and if the first redirection is a stdin (fd 0) input only (<
, <<
or <<<
) redirection, so:
$(< file)
$(0< file)
$(<&3)
(also$(0>&3)
actually as that's in effect the same operator)$(< file > foo 2> $(whatever))
but not:
$(> foo < file)
- nor
$(0<> file)
- nor
$(< file; sleep 1)
- nor
$(< file; < file2)
then
- all but the first redirection are ignored (they are parsed away)
- and it expands to the content of the file/heredoc/herestring (or whatever can be read from the file descriptor if using things like
<&3
) minus the trailing newline characters.
as if using $(cat < file)
except that
- the reading is done internally by the shell and not by
cat
- no pipe nor extra process is involved
- as a consequence of the above, since the code inside is not run in a subshell, any modification remain thereafter (as in
$(<${file=foo.txt})
or$(<file$((++n)))
) - read errors (though not errors while opening files or duplicating file descriptors) are silently ignored.
In zsh
, it's the same except that that special behaviour is only triggered when there's only one file input redirection (<file
or 0< file
, no <&3
, <<<here
, < a < b
...)
However, except when emulating other shells, in:
< file
<&3
<<< here...
that is when there are only input redirections without commands, outside of command substitution, zsh
runs the $READNULLCMD
(a pager by default), and when there are both input and output redirections, the $NULLCMD
(cat
by default), so even if $(<&3)
is not recognized as that special operator, it will still work like in ksh
though by invoking a pager to do it (that pager acting like cat
since its stdout will be a pipe).
However while ksh
's $(< a < b)
would expand to the content of a
, in zsh
, it expands to the content of a
and b
(or just b
if the multios
option is disabled), $(< a > b)
would copy a
to b
and expand to nothing, etc.
bash
has a similar operator but with a few differences:
comments are allowed before but not after:
echo "$(
# getting the content of file
< file)"
works but:
echo "$(< file
# getting the content of file
)"
expands to nothing.
like in
zsh
, only one file stdin redirection, though there's no fall back to a$READNULLCMD
, so$(<&3)
,$(< a < b)
do perform the redirections but expand to nothing.- for some reason, while
bash
does not invokecat
, it still forks a process that feeds the content of the file through a pipe making it much less of an optimisation than in other shells. It's in effect like a$(cat < file)
wherecat
would be a builtincat
. - as a consequence of the above, any change made within are lost afterwards (in the
$(<${file=foo.txt})
, mentioned above for instance, that$file
assignment is lost afterwards).
In bash
, IFS= read -rd '' var < file
(also works in zsh
) is a more effective way to read the content of a text file into a variable. It also has the benefit of preserving the trailing newline characters. See also $mapfile[file]
in zsh
(in the zsh/mapfile
module and only for regular files) which also works with binary files.
Note that the pdksh-based variants of ksh
have a few variations compared to ksh93. Of interest, in mksh
(one of those pdksh-derived shells), in
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
is optimised in that the content of the here document (without the trailing characters) is expanded without a temporary file or pipe being used as is otherwise the case for here documents, which makes it an effective multi-line quoting syntax.
To be portable to all versions of ksh
, zsh
and bash
, best is to limit to only $(<file)
avoiding comments and bearing in mind that modifications to variables made within may or may not be preserved.
Is it correct that$(<)
is an operator on filenames? Is<
in$(<)
a redirection operator, or not an operator on its own, and must be part of the entire operator$(<)
?
– Tim
Aug 23 '17 at 21:32
@Tim, it doesn't matter much how you want to call them.$(<file)
is meant to expand to the content offile
in a similar way as$(cat < file)
would. How it's done varies from shell to shell which is described at length in the answer. If you like, you can say that it's a special operator that is triggered when what looks like a command substitution (syntactically) contains what looks like a single stdin redirection (syntactically), but again with caveats and variations depending on the shell as listed here.
– Stéphane Chazelas
Aug 24 '17 at 8:21
@StéphaneChazelas: Fascinating, as usual; I’ve bookmarked this. So,n<&m
andn>&m
do the same thing? I didn’t know that, but I guess it’s not too surprising.
– Scott
Sep 3 '17 at 5:45
@Scott, yes, they both do adup(m, n)
. I can see some evidence of ksh86 using stdio and somefdopen(fd, "r" or "w")
, so it might have mattered then. But using stdio in a shell makes little sense, so I don't expect you'll find any modern shell where that will make a difference. One difference is that>&n
isdup(n, 1)
(short for1>&n
), while<&n
isdup(n, 0)
(short for0<&n
).
– Stéphane Chazelas
Sep 3 '17 at 9:08
Right. Except, of course, the two-argument form of the file descriptor duplication call is calleddup2()
;dup()
takes only one argument and, likeopen()
, uses the lowest available file descriptor. (Today I learned that there is adup3()
function.)
– Scott
Sep 3 '17 at 15:52
|
show 3 more comments
$(<file)
(also works with `<file`
) is a special operator of the Korn shell copied by zsh
and bash
. It does look a lot like command substitution but it's not really.
In POSIX shells, a simple command is:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
All parts are optional, you can have redirections only, command only, assignment only or combinations.
If there are redirections but no command, the redirections are performed (so a > file
would open and truncate file
), but then nothing happens. So
< file
Opens file
for reading, but then nothing happens as there's no command. So the file
is then closed and that's it. If $(< file)
was a simple command substitution, then it would expand to nothing.
In the POSIX specification, in $(script)
, if script
consists only of redirections, that produces unspecified results. That's to allow that special behaviour of the Korn shell.
In ksh (here tested with ksh93u+
), if the script consists of one and only one simple command (though comments are allowed before and after) that consists only of redirections (no command, no assignment) and if the first redirection is a stdin (fd 0) input only (<
, <<
or <<<
) redirection, so:
$(< file)
$(0< file)
$(<&3)
(also$(0>&3)
actually as that's in effect the same operator)$(< file > foo 2> $(whatever))
but not:
$(> foo < file)
- nor
$(0<> file)
- nor
$(< file; sleep 1)
- nor
$(< file; < file2)
then
- all but the first redirection are ignored (they are parsed away)
- and it expands to the content of the file/heredoc/herestring (or whatever can be read from the file descriptor if using things like
<&3
) minus the trailing newline characters.
as if using $(cat < file)
except that
- the reading is done internally by the shell and not by
cat
- no pipe nor extra process is involved
- as a consequence of the above, since the code inside is not run in a subshell, any modification remain thereafter (as in
$(<${file=foo.txt})
or$(<file$((++n)))
) - read errors (though not errors while opening files or duplicating file descriptors) are silently ignored.
In zsh
, it's the same except that that special behaviour is only triggered when there's only one file input redirection (<file
or 0< file
, no <&3
, <<<here
, < a < b
...)
However, except when emulating other shells, in:
< file
<&3
<<< here...
that is when there are only input redirections without commands, outside of command substitution, zsh
runs the $READNULLCMD
(a pager by default), and when there are both input and output redirections, the $NULLCMD
(cat
by default), so even if $(<&3)
is not recognized as that special operator, it will still work like in ksh
though by invoking a pager to do it (that pager acting like cat
since its stdout will be a pipe).
However while ksh
's $(< a < b)
would expand to the content of a
, in zsh
, it expands to the content of a
and b
(or just b
if the multios
option is disabled), $(< a > b)
would copy a
to b
and expand to nothing, etc.
bash
has a similar operator but with a few differences:
comments are allowed before but not after:
echo "$(
# getting the content of file
< file)"
works but:
echo "$(< file
# getting the content of file
)"
expands to nothing.
like in
zsh
, only one file stdin redirection, though there's no fall back to a$READNULLCMD
, so$(<&3)
,$(< a < b)
do perform the redirections but expand to nothing.- for some reason, while
bash
does not invokecat
, it still forks a process that feeds the content of the file through a pipe making it much less of an optimisation than in other shells. It's in effect like a$(cat < file)
wherecat
would be a builtincat
. - as a consequence of the above, any change made within are lost afterwards (in the
$(<${file=foo.txt})
, mentioned above for instance, that$file
assignment is lost afterwards).
In bash
, IFS= read -rd '' var < file
(also works in zsh
) is a more effective way to read the content of a text file into a variable. It also has the benefit of preserving the trailing newline characters. See also $mapfile[file]
in zsh
(in the zsh/mapfile
module and only for regular files) which also works with binary files.
Note that the pdksh-based variants of ksh
have a few variations compared to ksh93. Of interest, in mksh
(one of those pdksh-derived shells), in
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
is optimised in that the content of the here document (without the trailing characters) is expanded without a temporary file or pipe being used as is otherwise the case for here documents, which makes it an effective multi-line quoting syntax.
To be portable to all versions of ksh
, zsh
and bash
, best is to limit to only $(<file)
avoiding comments and bearing in mind that modifications to variables made within may or may not be preserved.
Is it correct that$(<)
is an operator on filenames? Is<
in$(<)
a redirection operator, or not an operator on its own, and must be part of the entire operator$(<)
?
– Tim
Aug 23 '17 at 21:32
@Tim, it doesn't matter much how you want to call them.$(<file)
is meant to expand to the content offile
in a similar way as$(cat < file)
would. How it's done varies from shell to shell which is described at length in the answer. If you like, you can say that it's a special operator that is triggered when what looks like a command substitution (syntactically) contains what looks like a single stdin redirection (syntactically), but again with caveats and variations depending on the shell as listed here.
– Stéphane Chazelas
Aug 24 '17 at 8:21
@StéphaneChazelas: Fascinating, as usual; I’ve bookmarked this. So,n<&m
andn>&m
do the same thing? I didn’t know that, but I guess it’s not too surprising.
– Scott
Sep 3 '17 at 5:45
@Scott, yes, they both do adup(m, n)
. I can see some evidence of ksh86 using stdio and somefdopen(fd, "r" or "w")
, so it might have mattered then. But using stdio in a shell makes little sense, so I don't expect you'll find any modern shell where that will make a difference. One difference is that>&n
isdup(n, 1)
(short for1>&n
), while<&n
isdup(n, 0)
(short for0<&n
).
– Stéphane Chazelas
Sep 3 '17 at 9:08
Right. Except, of course, the two-argument form of the file descriptor duplication call is calleddup2()
;dup()
takes only one argument and, likeopen()
, uses the lowest available file descriptor. (Today I learned that there is adup3()
function.)
– Scott
Sep 3 '17 at 15:52
|
show 3 more comments
$(<file)
(also works with `<file`
) is a special operator of the Korn shell copied by zsh
and bash
. It does look a lot like command substitution but it's not really.
In POSIX shells, a simple command is:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
All parts are optional, you can have redirections only, command only, assignment only or combinations.
If there are redirections but no command, the redirections are performed (so a > file
would open and truncate file
), but then nothing happens. So
< file
Opens file
for reading, but then nothing happens as there's no command. So the file
is then closed and that's it. If $(< file)
was a simple command substitution, then it would expand to nothing.
In the POSIX specification, in $(script)
, if script
consists only of redirections, that produces unspecified results. That's to allow that special behaviour of the Korn shell.
In ksh (here tested with ksh93u+
), if the script consists of one and only one simple command (though comments are allowed before and after) that consists only of redirections (no command, no assignment) and if the first redirection is a stdin (fd 0) input only (<
, <<
or <<<
) redirection, so:
$(< file)
$(0< file)
$(<&3)
(also$(0>&3)
actually as that's in effect the same operator)$(< file > foo 2> $(whatever))
but not:
$(> foo < file)
- nor
$(0<> file)
- nor
$(< file; sleep 1)
- nor
$(< file; < file2)
then
- all but the first redirection are ignored (they are parsed away)
- and it expands to the content of the file/heredoc/herestring (or whatever can be read from the file descriptor if using things like
<&3
) minus the trailing newline characters.
as if using $(cat < file)
except that
- the reading is done internally by the shell and not by
cat
- no pipe nor extra process is involved
- as a consequence of the above, since the code inside is not run in a subshell, any modification remain thereafter (as in
$(<${file=foo.txt})
or$(<file$((++n)))
) - read errors (though not errors while opening files or duplicating file descriptors) are silently ignored.
In zsh
, it's the same except that that special behaviour is only triggered when there's only one file input redirection (<file
or 0< file
, no <&3
, <<<here
, < a < b
...)
However, except when emulating other shells, in:
< file
<&3
<<< here...
that is when there are only input redirections without commands, outside of command substitution, zsh
runs the $READNULLCMD
(a pager by default), and when there are both input and output redirections, the $NULLCMD
(cat
by default), so even if $(<&3)
is not recognized as that special operator, it will still work like in ksh
though by invoking a pager to do it (that pager acting like cat
since its stdout will be a pipe).
However while ksh
's $(< a < b)
would expand to the content of a
, in zsh
, it expands to the content of a
and b
(or just b
if the multios
option is disabled), $(< a > b)
would copy a
to b
and expand to nothing, etc.
bash
has a similar operator but with a few differences:
comments are allowed before but not after:
echo "$(
# getting the content of file
< file)"
works but:
echo "$(< file
# getting the content of file
)"
expands to nothing.
like in
zsh
, only one file stdin redirection, though there's no fall back to a$READNULLCMD
, so$(<&3)
,$(< a < b)
do perform the redirections but expand to nothing.- for some reason, while
bash
does not invokecat
, it still forks a process that feeds the content of the file through a pipe making it much less of an optimisation than in other shells. It's in effect like a$(cat < file)
wherecat
would be a builtincat
. - as a consequence of the above, any change made within are lost afterwards (in the
$(<${file=foo.txt})
, mentioned above for instance, that$file
assignment is lost afterwards).
In bash
, IFS= read -rd '' var < file
(also works in zsh
) is a more effective way to read the content of a text file into a variable. It also has the benefit of preserving the trailing newline characters. See also $mapfile[file]
in zsh
(in the zsh/mapfile
module and only for regular files) which also works with binary files.
Note that the pdksh-based variants of ksh
have a few variations compared to ksh93. Of interest, in mksh
(one of those pdksh-derived shells), in
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
is optimised in that the content of the here document (without the trailing characters) is expanded without a temporary file or pipe being used as is otherwise the case for here documents, which makes it an effective multi-line quoting syntax.
To be portable to all versions of ksh
, zsh
and bash
, best is to limit to only $(<file)
avoiding comments and bearing in mind that modifications to variables made within may or may not be preserved.
$(<file)
(also works with `<file`
) is a special operator of the Korn shell copied by zsh
and bash
. It does look a lot like command substitution but it's not really.
In POSIX shells, a simple command is:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
All parts are optional, you can have redirections only, command only, assignment only or combinations.
If there are redirections but no command, the redirections are performed (so a > file
would open and truncate file
), but then nothing happens. So
< file
Opens file
for reading, but then nothing happens as there's no command. So the file
is then closed and that's it. If $(< file)
was a simple command substitution, then it would expand to nothing.
In the POSIX specification, in $(script)
, if script
consists only of redirections, that produces unspecified results. That's to allow that special behaviour of the Korn shell.
In ksh (here tested with ksh93u+
), if the script consists of one and only one simple command (though comments are allowed before and after) that consists only of redirections (no command, no assignment) and if the first redirection is a stdin (fd 0) input only (<
, <<
or <<<
) redirection, so:
$(< file)
$(0< file)
$(<&3)
(also$(0>&3)
actually as that's in effect the same operator)$(< file > foo 2> $(whatever))
but not:
$(> foo < file)
- nor
$(0<> file)
- nor
$(< file; sleep 1)
- nor
$(< file; < file2)
then
- all but the first redirection are ignored (they are parsed away)
- and it expands to the content of the file/heredoc/herestring (or whatever can be read from the file descriptor if using things like
<&3
) minus the trailing newline characters.
as if using $(cat < file)
except that
- the reading is done internally by the shell and not by
cat
- no pipe nor extra process is involved
- as a consequence of the above, since the code inside is not run in a subshell, any modification remain thereafter (as in
$(<${file=foo.txt})
or$(<file$((++n)))
) - read errors (though not errors while opening files or duplicating file descriptors) are silently ignored.
In zsh
, it's the same except that that special behaviour is only triggered when there's only one file input redirection (<file
or 0< file
, no <&3
, <<<here
, < a < b
...)
However, except when emulating other shells, in:
< file
<&3
<<< here...
that is when there are only input redirections without commands, outside of command substitution, zsh
runs the $READNULLCMD
(a pager by default), and when there are both input and output redirections, the $NULLCMD
(cat
by default), so even if $(<&3)
is not recognized as that special operator, it will still work like in ksh
though by invoking a pager to do it (that pager acting like cat
since its stdout will be a pipe).
However while ksh
's $(< a < b)
would expand to the content of a
, in zsh
, it expands to the content of a
and b
(or just b
if the multios
option is disabled), $(< a > b)
would copy a
to b
and expand to nothing, etc.
bash
has a similar operator but with a few differences:
comments are allowed before but not after:
echo "$(
# getting the content of file
< file)"
works but:
echo "$(< file
# getting the content of file
)"
expands to nothing.
like in
zsh
, only one file stdin redirection, though there's no fall back to a$READNULLCMD
, so$(<&3)
,$(< a < b)
do perform the redirections but expand to nothing.- for some reason, while
bash
does not invokecat
, it still forks a process that feeds the content of the file through a pipe making it much less of an optimisation than in other shells. It's in effect like a$(cat < file)
wherecat
would be a builtincat
. - as a consequence of the above, any change made within are lost afterwards (in the
$(<${file=foo.txt})
, mentioned above for instance, that$file
assignment is lost afterwards).
In bash
, IFS= read -rd '' var < file
(also works in zsh
) is a more effective way to read the content of a text file into a variable. It also has the benefit of preserving the trailing newline characters. See also $mapfile[file]
in zsh
(in the zsh/mapfile
module and only for regular files) which also works with binary files.
Note that the pdksh-based variants of ksh
have a few variations compared to ksh93. Of interest, in mksh
(one of those pdksh-derived shells), in
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
is optimised in that the content of the here document (without the trailing characters) is expanded without a temporary file or pipe being used as is otherwise the case for here documents, which makes it an effective multi-line quoting syntax.
To be portable to all versions of ksh
, zsh
and bash
, best is to limit to only $(<file)
avoiding comments and bearing in mind that modifications to variables made within may or may not be preserved.
edited 17 mins ago
answered Jun 1 '17 at 21:40
Stéphane ChazelasStéphane Chazelas
306k57579933
306k57579933
Is it correct that$(<)
is an operator on filenames? Is<
in$(<)
a redirection operator, or not an operator on its own, and must be part of the entire operator$(<)
?
– Tim
Aug 23 '17 at 21:32
@Tim, it doesn't matter much how you want to call them.$(<file)
is meant to expand to the content offile
in a similar way as$(cat < file)
would. How it's done varies from shell to shell which is described at length in the answer. If you like, you can say that it's a special operator that is triggered when what looks like a command substitution (syntactically) contains what looks like a single stdin redirection (syntactically), but again with caveats and variations depending on the shell as listed here.
– Stéphane Chazelas
Aug 24 '17 at 8:21
@StéphaneChazelas: Fascinating, as usual; I’ve bookmarked this. So,n<&m
andn>&m
do the same thing? I didn’t know that, but I guess it’s not too surprising.
– Scott
Sep 3 '17 at 5:45
@Scott, yes, they both do adup(m, n)
. I can see some evidence of ksh86 using stdio and somefdopen(fd, "r" or "w")
, so it might have mattered then. But using stdio in a shell makes little sense, so I don't expect you'll find any modern shell where that will make a difference. One difference is that>&n
isdup(n, 1)
(short for1>&n
), while<&n
isdup(n, 0)
(short for0<&n
).
– Stéphane Chazelas
Sep 3 '17 at 9:08
Right. Except, of course, the two-argument form of the file descriptor duplication call is calleddup2()
;dup()
takes only one argument and, likeopen()
, uses the lowest available file descriptor. (Today I learned that there is adup3()
function.)
– Scott
Sep 3 '17 at 15:52
|
show 3 more comments
Is it correct that$(<)
is an operator on filenames? Is<
in$(<)
a redirection operator, or not an operator on its own, and must be part of the entire operator$(<)
?
– Tim
Aug 23 '17 at 21:32
@Tim, it doesn't matter much how you want to call them.$(<file)
is meant to expand to the content offile
in a similar way as$(cat < file)
would. How it's done varies from shell to shell which is described at length in the answer. If you like, you can say that it's a special operator that is triggered when what looks like a command substitution (syntactically) contains what looks like a single stdin redirection (syntactically), but again with caveats and variations depending on the shell as listed here.
– Stéphane Chazelas
Aug 24 '17 at 8:21
@StéphaneChazelas: Fascinating, as usual; I’ve bookmarked this. So,n<&m
andn>&m
do the same thing? I didn’t know that, but I guess it’s not too surprising.
– Scott
Sep 3 '17 at 5:45
@Scott, yes, they both do adup(m, n)
. I can see some evidence of ksh86 using stdio and somefdopen(fd, "r" or "w")
, so it might have mattered then. But using stdio in a shell makes little sense, so I don't expect you'll find any modern shell where that will make a difference. One difference is that>&n
isdup(n, 1)
(short for1>&n
), while<&n
isdup(n, 0)
(short for0<&n
).
– Stéphane Chazelas
Sep 3 '17 at 9:08
Right. Except, of course, the two-argument form of the file descriptor duplication call is calleddup2()
;dup()
takes only one argument and, likeopen()
, uses the lowest available file descriptor. (Today I learned that there is adup3()
function.)
– Scott
Sep 3 '17 at 15:52
Is it correct that
$(<)
is an operator on filenames? Is <
in $(<)
a redirection operator, or not an operator on its own, and must be part of the entire operator $(<)
?– Tim
Aug 23 '17 at 21:32
Is it correct that
$(<)
is an operator on filenames? Is <
in $(<)
a redirection operator, or not an operator on its own, and must be part of the entire operator $(<)
?– Tim
Aug 23 '17 at 21:32
@Tim, it doesn't matter much how you want to call them.
$(<file)
is meant to expand to the content of file
in a similar way as $(cat < file)
would. How it's done varies from shell to shell which is described at length in the answer. If you like, you can say that it's a special operator that is triggered when what looks like a command substitution (syntactically) contains what looks like a single stdin redirection (syntactically), but again with caveats and variations depending on the shell as listed here.– Stéphane Chazelas
Aug 24 '17 at 8:21
@Tim, it doesn't matter much how you want to call them.
$(<file)
is meant to expand to the content of file
in a similar way as $(cat < file)
would. How it's done varies from shell to shell which is described at length in the answer. If you like, you can say that it's a special operator that is triggered when what looks like a command substitution (syntactically) contains what looks like a single stdin redirection (syntactically), but again with caveats and variations depending on the shell as listed here.– Stéphane Chazelas
Aug 24 '17 at 8:21
@StéphaneChazelas: Fascinating, as usual; I’ve bookmarked this. So,
n<&m
and n>&m
do the same thing? I didn’t know that, but I guess it’s not too surprising.– Scott
Sep 3 '17 at 5:45
@StéphaneChazelas: Fascinating, as usual; I’ve bookmarked this. So,
n<&m
and n>&m
do the same thing? I didn’t know that, but I guess it’s not too surprising.– Scott
Sep 3 '17 at 5:45
@Scott, yes, they both do a
dup(m, n)
. I can see some evidence of ksh86 using stdio and some fdopen(fd, "r" or "w")
, so it might have mattered then. But using stdio in a shell makes little sense, so I don't expect you'll find any modern shell where that will make a difference. One difference is that >&n
is dup(n, 1)
(short for 1>&n
), while <&n
is dup(n, 0)
(short for 0<&n
).– Stéphane Chazelas
Sep 3 '17 at 9:08
@Scott, yes, they both do a
dup(m, n)
. I can see some evidence of ksh86 using stdio and some fdopen(fd, "r" or "w")
, so it might have mattered then. But using stdio in a shell makes little sense, so I don't expect you'll find any modern shell where that will make a difference. One difference is that >&n
is dup(n, 1)
(short for 1>&n
), while <&n
is dup(n, 0)
(short for 0<&n
).– Stéphane Chazelas
Sep 3 '17 at 9:08
Right. Except, of course, the two-argument form of the file descriptor duplication call is called
dup2()
; dup()
takes only one argument and, like open()
, uses the lowest available file descriptor. (Today I learned that there is a dup3()
function.)– Scott
Sep 3 '17 at 15:52
Right. Except, of course, the two-argument form of the file descriptor duplication call is called
dup2()
; dup()
takes only one argument and, like open()
, uses the lowest available file descriptor. (Today I learned that there is a dup3()
function.)– Scott
Sep 3 '17 at 15:52
|
show 3 more comments
Because bash
does it internally for you, expanded the filename and cats the file to standard output, like if you were to do $(cat < filename)
. It's a bash feature, maybe you need to look into the bash
source code to know exactly how it works.
Here the the function to handle this feature (From bash
source code, file builtins/evalstring.c
):
/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */
static int
cat_file (r)
REDIRECT *r;
{
char *fn;
int fd, rval;
if (r->instruction != r_input_direction)
return -1;
/* Get the filename. */
if (posixly_correct && !interactive_shell)
disallow_filename_globbing++;
fn = redirection_expand (r->redirectee.filename);
if (posixly_correct && !interactive_shell)
disallow_filename_globbing--;
if (fn == 0)
{
redirection_error (r, AMBIGUOUS_REDIRECT);
return -1;
}
fd = open(fn, O_RDONLY);
if (fd < 0)
{
file_error (fn);
free (fn);
return -1;
}
rval = zcatfd (fd, 1, fn);
free (fn);
close (fd);
return (rval);
}
A note that $(<filename)
is not exactly equivalent to $(cat filename)
; the latter will fail if the filename starts with a dash -
.
$(<filename)
was originally from ksh
, and was added to bash
from Bash-2.02
.
1
cat filename
will fail if the filename starts with a dash because cat accepts options. You can work around that on most modern systems withcat -- filename
.
– Adam Katz
Jul 6 '17 at 1:20
add a comment |
Because bash
does it internally for you, expanded the filename and cats the file to standard output, like if you were to do $(cat < filename)
. It's a bash feature, maybe you need to look into the bash
source code to know exactly how it works.
Here the the function to handle this feature (From bash
source code, file builtins/evalstring.c
):
/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */
static int
cat_file (r)
REDIRECT *r;
{
char *fn;
int fd, rval;
if (r->instruction != r_input_direction)
return -1;
/* Get the filename. */
if (posixly_correct && !interactive_shell)
disallow_filename_globbing++;
fn = redirection_expand (r->redirectee.filename);
if (posixly_correct && !interactive_shell)
disallow_filename_globbing--;
if (fn == 0)
{
redirection_error (r, AMBIGUOUS_REDIRECT);
return -1;
}
fd = open(fn, O_RDONLY);
if (fd < 0)
{
file_error (fn);
free (fn);
return -1;
}
rval = zcatfd (fd, 1, fn);
free (fn);
close (fd);
return (rval);
}
A note that $(<filename)
is not exactly equivalent to $(cat filename)
; the latter will fail if the filename starts with a dash -
.
$(<filename)
was originally from ksh
, and was added to bash
from Bash-2.02
.
1
cat filename
will fail if the filename starts with a dash because cat accepts options. You can work around that on most modern systems withcat -- filename
.
– Adam Katz
Jul 6 '17 at 1:20
add a comment |
Because bash
does it internally for you, expanded the filename and cats the file to standard output, like if you were to do $(cat < filename)
. It's a bash feature, maybe you need to look into the bash
source code to know exactly how it works.
Here the the function to handle this feature (From bash
source code, file builtins/evalstring.c
):
/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */
static int
cat_file (r)
REDIRECT *r;
{
char *fn;
int fd, rval;
if (r->instruction != r_input_direction)
return -1;
/* Get the filename. */
if (posixly_correct && !interactive_shell)
disallow_filename_globbing++;
fn = redirection_expand (r->redirectee.filename);
if (posixly_correct && !interactive_shell)
disallow_filename_globbing--;
if (fn == 0)
{
redirection_error (r, AMBIGUOUS_REDIRECT);
return -1;
}
fd = open(fn, O_RDONLY);
if (fd < 0)
{
file_error (fn);
free (fn);
return -1;
}
rval = zcatfd (fd, 1, fn);
free (fn);
close (fd);
return (rval);
}
A note that $(<filename)
is not exactly equivalent to $(cat filename)
; the latter will fail if the filename starts with a dash -
.
$(<filename)
was originally from ksh
, and was added to bash
from Bash-2.02
.
Because bash
does it internally for you, expanded the filename and cats the file to standard output, like if you were to do $(cat < filename)
. It's a bash feature, maybe you need to look into the bash
source code to know exactly how it works.
Here the the function to handle this feature (From bash
source code, file builtins/evalstring.c
):
/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */
static int
cat_file (r)
REDIRECT *r;
{
char *fn;
int fd, rval;
if (r->instruction != r_input_direction)
return -1;
/* Get the filename. */
if (posixly_correct && !interactive_shell)
disallow_filename_globbing++;
fn = redirection_expand (r->redirectee.filename);
if (posixly_correct && !interactive_shell)
disallow_filename_globbing--;
if (fn == 0)
{
redirection_error (r, AMBIGUOUS_REDIRECT);
return -1;
}
fd = open(fn, O_RDONLY);
if (fd < 0)
{
file_error (fn);
free (fn);
return -1;
}
rval = zcatfd (fd, 1, fn);
free (fn);
close (fd);
return (rval);
}
A note that $(<filename)
is not exactly equivalent to $(cat filename)
; the latter will fail if the filename starts with a dash -
.
$(<filename)
was originally from ksh
, and was added to bash
from Bash-2.02
.
edited Mar 13 '15 at 6:55
answered Mar 12 '15 at 18:56
cuonglmcuonglm
104k24205302
104k24205302
1
cat filename
will fail if the filename starts with a dash because cat accepts options. You can work around that on most modern systems withcat -- filename
.
– Adam Katz
Jul 6 '17 at 1:20
add a comment |
1
cat filename
will fail if the filename starts with a dash because cat accepts options. You can work around that on most modern systems withcat -- filename
.
– Adam Katz
Jul 6 '17 at 1:20
1
1
cat filename
will fail if the filename starts with a dash because cat accepts options. You can work around that on most modern systems with cat -- filename
.– Adam Katz
Jul 6 '17 at 1:20
cat filename
will fail if the filename starts with a dash because cat accepts options. You can work around that on most modern systems with cat -- filename
.– Adam Katz
Jul 6 '17 at 1:20
add a comment |
Think of command substitution as running a command as usual and dumping the output at the point where you are running the command.
The output of commands can be used as arguments to another command, to
set a variable, and even for generating the argument list in a for
loop.
foo=$(echo "bar")
will set value of the variable $foo
to bar
; the output of the command echo bar
.
Command Substitution
1
I believe that it’s fairly clear from the question that the OP understands the basics of command substitution; the question is about the special case of$(< file)
, and he doesn't need a tutorial on the general case. If you are saying that$(< file)
is just an ordinary case of$(command)
with a command of< file
, then you are saying the same thing Adam Katz is saying, and you are both wrong.
– Scott
Sep 3 '17 at 5:44
add a comment |
Think of command substitution as running a command as usual and dumping the output at the point where you are running the command.
The output of commands can be used as arguments to another command, to
set a variable, and even for generating the argument list in a for
loop.
foo=$(echo "bar")
will set value of the variable $foo
to bar
; the output of the command echo bar
.
Command Substitution
1
I believe that it’s fairly clear from the question that the OP understands the basics of command substitution; the question is about the special case of$(< file)
, and he doesn't need a tutorial on the general case. If you are saying that$(< file)
is just an ordinary case of$(command)
with a command of< file
, then you are saying the same thing Adam Katz is saying, and you are both wrong.
– Scott
Sep 3 '17 at 5:44
add a comment |
Think of command substitution as running a command as usual and dumping the output at the point where you are running the command.
The output of commands can be used as arguments to another command, to
set a variable, and even for generating the argument list in a for
loop.
foo=$(echo "bar")
will set value of the variable $foo
to bar
; the output of the command echo bar
.
Command Substitution
Think of command substitution as running a command as usual and dumping the output at the point where you are running the command.
The output of commands can be used as arguments to another command, to
set a variable, and even for generating the argument list in a for
loop.
foo=$(echo "bar")
will set value of the variable $foo
to bar
; the output of the command echo bar
.
Command Substitution
answered Mar 13 '15 at 3:48
iyriniyrin
1,545621
1,545621
1
I believe that it’s fairly clear from the question that the OP understands the basics of command substitution; the question is about the special case of$(< file)
, and he doesn't need a tutorial on the general case. If you are saying that$(< file)
is just an ordinary case of$(command)
with a command of< file
, then you are saying the same thing Adam Katz is saying, and you are both wrong.
– Scott
Sep 3 '17 at 5:44
add a comment |
1
I believe that it’s fairly clear from the question that the OP understands the basics of command substitution; the question is about the special case of$(< file)
, and he doesn't need a tutorial on the general case. If you are saying that$(< file)
is just an ordinary case of$(command)
with a command of< file
, then you are saying the same thing Adam Katz is saying, and you are both wrong.
– Scott
Sep 3 '17 at 5:44
1
1
I believe that it’s fairly clear from the question that the OP understands the basics of command substitution; the question is about the special case of
$(< file)
, and he doesn't need a tutorial on the general case. If you are saying that $(< file)
is just an ordinary case of $(command)
with a command of < file
, then you are saying the same thing Adam Katz is saying, and you are both wrong.– Scott
Sep 3 '17 at 5:44
I believe that it’s fairly clear from the question that the OP understands the basics of command substitution; the question is about the special case of
$(< file)
, and he doesn't need a tutorial on the general case. If you are saying that $(< file)
is just an ordinary case of $(command)
with a command of < file
, then you are saying the same thing Adam Katz is saying, and you are both wrong.– Scott
Sep 3 '17 at 5:44
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f189749%2funderstanding-bashs-read-a-file-command-substitution%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown