What is the difference between $(< filename ) and $( cat filename ) ? :rolleyes:
Or should i ask ... are they equivalent ?
I can't give you a quantitative answer, but cite man bash
:
$(< filename )
- shell opens the file. $( cat filename )
- cat opens the file.
Create a simple script:-
#!/bin/ksh -xv
var1=$( cat file )
var2=$( < file )
and run strace
to understand the difference:-
strace ./script.ksh 2> strace.out
Run strace with -f (follow child processes) to see the full overhead.
-f
was important to get the real picture!
They are only equivalent in bash, ksh93 and zsh. $(< file)
is faster than $(cat file)
, but the latter is POSIX compliant whereas the former is not.
Just for fun playing with subsequent args ... consider giving a try to:
# for i in $(seq 1 10) ; do echo $(< /dev/urandom tr -dc '[:alnum:],@#:!?+-' | head -c10) ; done
# for i in $(seq 1 10) ; do echo $(cat /dev/urandom -- tr -dc '[:alnum:],@#:!?+-' | head -c10) ; done
# for i in $(seq 1 10) ; do echo $(cat /dev/urandom | tr -dc '[:alnum:],@#:!?+-' | head -c10) ; done
# for i in $(seq 1 10) ; do echo $(< /dev/urandom | tr -dc '[:alnum:],@#:!?+-' | head -c10) ; done
It does not work that way. $(<file)
is a special case, which is a faster alternative to $(cat file)
. If you are using anything other than just a file, it becomes something else. $( ... )
is just command sustitution, so if we leave out that, it becomes:
< /dev/urandom tr -dc '[:alnum:],@#:!?+-' | head -c10
This is the same as tr -dc '[:alnum:],@#:!?+-' < /dev/urandom | head -c10
cat /dev/urandom -- tr -dc '[:alnum:],@#:!?+-' | head -c10
This is strange, it effectively just means cat /dev/urandom | head -c10
cat /dev/urandom | tr -dc '[:alnum:],@#:!?+-' | head -c10
This is the same as the first one with UUOC
< /dev/urandom | tr -dc '[:alnum:],@#:!?+-' | head -c10
This is equivalent to :< /dev/urandom | tr -dc '[:alnum:],@#:!?+-' | head -c10
, which is that same as :
: | tr -dc '[:alnum:],@#:!?+-' | head -c10
It is. In fact, tr -dc etc.
are interpreted as input files
cat: tr: No such file or directory
cat: -dc: No such file or directory
cat: '[:alnum:],@#:!?+-': No such file or directory
and generate error messages which are suppressed in above case as /dev/urandom
never ends and the pipe is chopped off by the head -c10
from the other side.
Yeah, I agree with you regarding the UUOC one.
The test with -- was just bulk try just to see if it would get the -- as an end of options and see how it would handle the rest of the command line.
I ran it on an AIX machine which didn't return an error message, but a fooled output instead, with some strange control character (the kind of output that sometimes may mess up your PuTTY screen ...)
As Yoda and Scruti noticed, I think the confusing point was that, $(< /dev/urandom tr -dc '[:alnum:],@#:!?+-' | head -c10 )
is not interpreted as the special case $(<filename)
but as the $( cmd )
This brings me to the question :
Does the special case $(<filename)
support only and strictly 1 file ?
Passing more than one file to the redirection wont be interpreted that way, the second file will just be understood as a command name.
$(< file1 file2)
Using more than one redirection lead to undefined behavior.
$(< file1 <file2)
-
ksh ignores all redirections but the first one, i.e. output file1. It doesn't check file2 for readability/existence.
-
bash silently ignores the whole command, i.e. output nothing, however, it returns an error if file1 or file2 isn't readable (or doesn't exists)
Obviously $( < filename )
copies the stream with a shell-internal, just like the external command $( cat < filename )
does.
For a concatenation of file1 and file2 you have to use the external command $( cat file1 file2 )
or a string concatenation like this:
s=$( < /etc/passwd )$( < /etc/group )
echo "$s"
Perhaps this is just an aside, but wouldn't redirecting from a named pipe work? That is, if in $(< file1)
file1
would be a named pipe being filled by cat file1 file2 ...
?
And second, wouldn't $(< $(cat file1 file2) )
also work? Right now i am travelling with this damn work-laptop and have no U*X-system at hand, so i can only speculate instead of trying....
bakunin