-1

I was wondering if there was anything special about < . in bash since

$ mail <destination> < .

sends an empty email instead of a dot and

$ echo < .

doesn't fit anything that I used to know about echo.

After tinkering around, I wonder how can you explain the behavior of echo in the following:

$ echo < => syntax error

$ echo < giberish => error: No such file or directory

$ echo < . giberish => giberish

$ echo < . => blank

$ echo < "filenameInPWD" => blank

$ echo < "randomstring" => error: No such file or directory

Katerl3s
  • 153
  • 1
    Do you know what < and . mean and you're asking about the combination, or is it just the whole lot that you're asking about? Alternatively, what are you expecting the first command to do, and what error were you expecting from the second? You can [edit] your question. – Michael Homer Oct 11 '20 at 03:10
  • I came to the conclusion that mail as in $ mail <dest> is just programmed to put an EOT when it sees a dot alone in a line; it doesn't have anything to do with bash, so I'll remove that from the question. Regarding echo I'll expand a bit on it. – Katerl3s Oct 11 '20 at 03:17
  • That's the wrong conclusion. If you want to see what's happening, run each program under strace so tht you can see the system calls (although the output is long and you will need patience and persistence to get through it). – NickD Oct 11 '20 at 03:22
  • @NickD I'm trying to thing what else it might be before I go through that. What I see after I type $ mail root is satisfyingly clear, even if I admit something intricate might be behind. – Katerl3s Oct 11 '20 at 03:38
  • I have tried to explain in my answer. – NickD Oct 11 '20 at 03:39
  • 1
    Now you have changed your question so that it is mostly about echo, rather than about the < . redirection. That makes my answer mostly irrelevant (although the answer by @thanasisp is still relevant and answers most of your new question). I wish people did not change questions after answers are submitted except to fix typos. – NickD Oct 11 '20 at 03:50
  • 1
    I think NickD is right, I suggest to add the initial question also, and include the modification after that, it's not very big totally. So any reader can understand why Nick's answer explains an example with the mail command etc. – thanasisp Oct 11 '20 at 03:58
  • I fixed it as you suggested, take a look – Katerl3s Oct 11 '20 at 04:03
  • 1
    I see still the initial question is missing, but never mind, you may leave it like this. Please remember in the future, to prepare you question, focus on one problem, take some time to review it and finally post it, so that you need to do only minimum changes and help answers from the beginning to focus into the problem you describe, cheers. – thanasisp Oct 11 '20 at 05:12

2 Answers2

2

The dot stands for the current directory, you can see that in typical usual commands like find ., cp path/filename . etc, it means "here". Also dot is the synonym of the source command, you can see that by typing man ..

In your case, dot is being used as the current directory, because this syntax:

command < path/to/something

is a redirection into the standard input of the command as you can see in the bash manual, while this syntax:

command < path/to/something argument

is the same as above, with additionally one argument, the same like this:

command argument < path/to/something

So in your case, echo does not complain because it does not read its standard input at all, reads only the following string and prints it.

You can see that better with other commands, for example tr that reads only its standard input:

tr < . 'a' 'b' # or tr 'a' 'b' < .
tr: read error: Is a directory
tr < file 'a' 'b' # works.
thanasisp
  • 8,122
  • can you please take a look at the edited question? – Katerl3s Oct 11 '20 at 03:30
  • 1
    I have seen that you modified the question, I think you can still find an answer for your main point above. Also follow the link to the bash manual: in the right side of this redirection a filename is expected, so the content of the file is being redirected. – thanasisp Oct 11 '20 at 03:35
  • 1
    To the OP: the important point to your (new) question is that "...echo...does not read its standard input at all" to quote from the answer. It only cares about the command line arguments and those can come before or after the (irrelevant in this case) input redirection. – NickD Oct 11 '20 at 03:53
2

If you do

strace mail <dest> < .

you can see what happened (although you have to look closely). On a Linux system (as a comment notes, other Unix systems may behave differently if a read of a directory succeeds), there are about 200 lines of output, much of it initialization, but there are three very significant lines, in my case lines 153, 165 and 191:

...
read(0, 0x556829edb730, 8192)           = -1 EISDIR (Is a directory)
...
write(1, "No message, no subject; hope tha"..., 39No message, no subject; hope that's ok) = 39
...
write(4, "Date: Sat, 10 Oct 2020 23:19:22 "..., 212) = 212
...
exit_group(0)                           = ?
+++ exited with 0 +++

IOW, it tried to read file descriptor 0 (its standard input) and got an error EISDIR: that's because the shell redirected . i.e. the current directory as its standard input and read is not allowed to read a directory. But the mail program ignored that error, wrote a message on its stdout (file descriptor 1) that there was no message and no subject submitted to it and that it hoped that that was OK, then proceeded to compose a mail message and write it to file descriptor 4, which presumably is plumbed up somehow to send the message (the message consists of 212 characters). Note also that the program exits with 0 status (normal exit).

If you try the same thing with cat or tr as @thanasisp suggests in his answer, you will see a slightly different result. Those programs still try to read from file descriptor 0 and get the EISDIR error - but they do NOT ignore the error; instead, they exit with an error message and non-zero status:

$ strace cat < .
...
read(0, 0x7fc27daec000, 131072)         = -1 EISDIR (Is a directory)
write(2, "cat: ", 5cat: )                    = 5
write(2, "-", 1-)                        = 1
openat(AT_FDCWD, "/usr/share/locale/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": Is a directory", 16: Is a directory)        = 16
write(2, "\n", 1
)                       = 1
munmap(0x7fc27daeb000, 139264)          = 0
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++

But there is no difference in how < . is treated: in both cases, the shell associates a file (the current directory) with file descriptor 0 (the standard input) of the executed program. But the programs choose to respond to the error differently. That's all.

And BTW, the answer by @thanasisp is spot-on and answers most of your questions (even if it elides a bit the subtle difference between the mail command and e.g. tr or cat, which is what I concentrate on in this answer).

NickD
  • 2,926
  • Honestly the most useful thing I've learned from this is strace and your usage demo to disambiguate the fact that the dot is the current working directory in this case (until your demo to me the dot could have been something else, like "source" as in https://tldp.org/LDP/abs/html/special-chars.html). I mean, I know that the dot in bash is usually the current working directory, that's one of the first things you learn. – Katerl3s Oct 11 '20 at 03:52
  • I'm glad you found it useful. – NickD Oct 11 '20 at 03:55
  • ... but I still think that the other answer is the correct answer to your (new) question. – NickD Oct 11 '20 at 04:12
  • @NickD Notice that on some Unix systems (FreeBSD, Solaris) reading a directory as an ordinary file may succeed -- and mail dest <. will get the filenames interspersed with binary junk, and may even send something ;-) –  Oct 11 '20 at 05:09
  • Thanks: added a note to that effect. Note that on Linux, mail does send something (an empty message), even though the read() returns an error. – NickD Oct 11 '20 at 13:00