We help IT Professionals succeed at work.

Why "less 0> /test.txt" doesn't output "Missing filename" (output redirection)?

Low Priority
179 Views
Last Modified: 2018-10-15
Let's start with a useless example of input redirection:

less 1< /test.txt

Open in new window


The result is:

Missing filename ("less --help" for help)

This I understand, because:

LESS-PROCESS:
FD 0 <- terminal file (keyboard)
FD 1 <- /test.txt
FD 2 -> terminal file (monitor)

FD 0 needs to get some content from a file, but there is no file in this case. There is /test.txt but it points to the wrong fd. Now let's take a look at a useless example of output redirection:

less 0> /test.txt

Open in new window


LESS-PROCESS:
FD 0 -> /test.txt
FD 1 -> terminal file (monitor)
FD 2 -> terminal file (monitor)

The program doesn't give file descriptor 0 some output, so "nothing" will be written to /test.txt. That why you will always end up with an empty /test.txt file. File descriptor 0 opens /test.txt for writing and not for reading. So the less-process doesn't get any file to read from. Then why the result is not:

Missing filename ("less --help" for help)

Instead, less is acting as it got an empty file as input. The file /test.txt is empty in the end, but this is about output redirection and not about input redirection, so there is no input. That's the reason why I would expect "Missing filename". Why this is not the case?
Comment
Watch Question

David FavorFractional CTO
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
Because less with no file will read STDIN, so your command above will either hang for every or produce a read error, depending on your exact version combo of - shell + less + Distro.

Using less is meant to interact with a TTY paging data, not a file.

You're looking for the cat command, rather than less or more or any other TTY based pager.

Author

Commented:
Because less with no file will read STDIN, so your command above will either hang for every or produce a read error, depending on your exact version combo of - shell + less + Distro.

This is incorrect, because then the result should be the same for:

less 1< /test.txt

Open in new window


and

less 0> /test.txt

Open in new window


But the results are not the same. And if less would read stdin, then it wouldn't complain about "Missing filename". This means that it is expecting a filename. And:

You're looking for the cat command, rather than less or more or any other TTY based pager.

I'm not looking for anything. I'm looking for an answer to my question ;).
nociSoftware Engineer
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
>word    - will create and empty file (write only)
>>word - will append to a file or create a file if it doesn't exist. (write only, possitioned at end of file)
<word   - the file must exist,  (read only)

using   less 0>t.t   should later yield IO errors when reads are attempted.
it will create t.t, open it to fd=0 then exec() less....
When less will read it will error out on a read error.
For simplicity i used cat here (less needs to much space on a page).

$
$ cat 0>t.0 
cat: -: Bad file descriptor
$  touch t.1
$ cat t.0 1<t.1
cat: write error: Bad file descriptor
$ rm t.1 t.0

Open in new window


Write only fd cannot be read, read only fd cannot be written.

Author

Commented:
Thanks again! Slowly I'm starting to see how you're answering questions ;). Just for this question, I'll explain what I meant in that other post.

You're saying:

>>word - will append to a file or create a file if it doesn't exist.

I know this, but it's completely irrelevant to the question, so why you're mentioning it? And for example:

<word   - the must exist, and should be r/o.

Why you're mentioning that? I'm not asking what <word means because I already know this. And what do you mean by:

"the must exist"?

And what exactly do you mean by "r/o", (read/only)? And if yes, then why you're saying:

>word    - will create and empty file

And not:

>word    - will create and empty file (write only)

But anyway, such information only distracts from the real question. Anyway in my example, the files did have contents. And why you're noticing:

it will create t.t, open it to fd=0 then exec() less....

This is how output redirects are working with respect to system calls, but that's also irrelevant to this question. It only distracts from the real question. It doesn't even "open" t.t. First it closes fd 0, then it calls dup(fd_create) and in the end it closes fd_create again. If I wouldn't be aware of it, such information would work counter-productive.

So far, only unnecessary information. Now let's take a look at:

When less will read it will error out on a read error.

That's the first information that is relevant for my question. I've made a mistake in my first question (sorry for that), I said:

Instead, less is acting as it got an empty file as input.

This should be:

Instead, less outputs:
read error (press RETURN)

So it's correct that there is a read error. But that's not yet an answer to my question (that's the observation what my question is about). So what is left is:

Write only fd cannot be read, read only fd cannot be written.

And what exactly do you mean by "Write only fd cannot be read, read only fd cannot be written."? Instead of all the other information you could make a whole sentence of this with some explanation what you mean by it. File descriptor 0 (standard input) is a "read only fd". The program does not write data to fd 0, but it only gets data from it (its standard input). Do you mean this? Because then it's also irrelevant information, because I'm already aware of this. That's why I call my example "useless" (pure for theory). But this is also irrelevant.

 The results we need to explain in summary:

less 1< /test.txt       -> Missing filename
less 0> /test.txt       -> read error

Why I got different results? That's the question. Why both examples do not display "read error"? Or why both don't display "Missing filename"?
nociSoftware Engineer
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
>word will create the file (write only)  ==> hence no error about non existent file.....   you knew that, but complain that is doesn't say missing file.... if it is missing it will create one. obviously that escaped attention...
the 0 is irrelevant for THAT part.......   (and that is exactly what i mean with: " >word... etc."

the less program expects to be able to read the fd..., it has a write flag on it (> opens write only) ==> read error...... (hence a write only fd cannot be read).

Then the 1<word case... open a non existing file for read... => which fails because the file does not exist.... the SHELL will fail before less is even attempted to be started.  hence missing  missing filename.
Then there still is the unsolved case, not mentioned... but relevant in context: what if the wile opened for read did exist...., what would happen..
I showed that with the cat example which also says that the file cannot be written.  write error, bad descriptor... (cat is easier to demonstrate these issues... less would do the same...).

This time  i did NOT write a long story no background, assuming it would be sufficient, only the exact answers... and you missed the answer... i only produced the relevant parts no extra info... What answer WOULD YOU ACCEPT....
and you are right for completeness (write only) should have been appended with >word and for
>>word this would be more accurate  (write only, with the file pointer at end of file) should also be the correct description for this context...
It is not 100% exactly what happens, but it is close enough to be correct in this context.

Author

Commented:
Thanks a lot again, noci!

>word will create the file (write only)  ==> hence no error about non existent file.....   you knew that, but complain that is doesn't say missing file.... if it is missing it will create one. obviously that escaped attention...
the 0 is irrelevant for THAT part.......   (and that is exactly what i mean with: " >word... etc."

Firstable, I already said that my example is about a non-empty file. We have:

less 0> /test.txt

Open in new window


So this creates:

       write
FD 0    ->    test.txt

However, this is different than:

       read
FD 0    <-    test.txt

In other words, there is no file that can be read. I know that there is "a" file, but it's a file to WRITE to. There is no file to READ from. So why I don't see "Missing filename"? Now you're saying:

the less program expects to be able to read the fd..., it has a write flag on it (> opens write only) ==> read error...... (hence a write only fd cannot be read).

Okay, now you're trying to answer my question. Does the less program not see that only a file (for writing to) is connected to the file descriptor? So it knows it misses a file (to read from)? In the end, there is no file/filename to read from? What you're saying is that the program just sees a file, then tries to read it, but then finds out that the file doesn't have read permissions, and this results in "read error"?

That would make sense as correct answer (although even now I really can not find the answer in your first post). You're saying:

This time  i did NOT write a long story no background

I think at least >>word and all the system calls were not really relevant for this question, but okay never mind ;). Anyway I think now you gave me the correct answer:

the less program expects to be able to read the fd..., it has a write flag on it (> opens write only) ==> read error...... (hence a write only fd cannot be read).

First, I was more thinking like this: the less program needs a file to read from, so it checks if there is a file with at least read-permissions. If there isn't a file with read-permissions, then the program will output "Missing filename". This is not that unlogical thought, right? It could work like that? But apparently it only checks whether there is a file, and if yes, then it starts to read (independent of file permissions). That's what makes it not 100% logical to me, because I would say, if you don't have permission to do something, don't start with it.

If I don't have "permissions" to kill someone, then I don't start with it to find out that I don't have permissions to it. Anyway I "accept" it's working like that in reality, so I don't have problems with it, but only to explain that the way I was thinking, is actually pretty logical. However, in reality it is apparently not working like that.
nociSoftware Engineer
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
The less program doesn't open the it just does read(0,buffer, sizeof(buffer)... it doesn't check that.  The read  gives the error.

It might be entertaining to run strace less ... that will tell exactly what less does (in terms of system calls).
there also is an ltrace program (ltrace less)  that will show the libc calls.

using 0>... isa violation of rules.. so the trespassing is  stopped when it is found out.  (some was pointed to a destionation to walk south..., now a guard (OS) tells  wrong way.. this is not acceptable.

Author

Commented:
I've marked the post that contains:

the less program expects to be able to read the fd..., it has a write flag on it (> opens write only) ==> read error...... (hence a write only fd cannot be read).

as the correct answer, because this showed me that the program doesn't check the file permissions first. Thanks a lot again for all your help!

P.S. Ah I just see that I can mark multiple posts as the correct answer, so I've marked the last two posts.

Author

Commented:
I slept over it for a night, but I realize that I don't understand it 100% yet. Now it's specifically about:

less 1< /test.txt       -> Missing filename

Correct me if I'm wrong, but this starts with something like this:

FD 0 <- /dev/pts/1
FD 1 <- /test.txt
FD 1 -> /dev/pts/1

So actually fd 0 is connected with a file (/dev/pts/1). Now I would expect that the program starts to read /dev/pts/1, but apparently this is not happening, because "Missing filename" is the output. However, "/dev/pts/1" is a file with a name, so apparently I have to see it differently?
nociSoftware Engineer
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
In your case the shell (less is not running....)
The shell parser had created a "simple command"  less 1< /text.txt
During opening of the /test.txt file  the shell finds it cannot find the file.
Then it doesn't even try do the exec().
IT Business Systems Analyst / Software Developer
CERTIFIED EXPERT
Top Expert 2015
Commented:
I will weigh in here because I see that last one differently... try this, just type "less" into the command line. You should get the same thing, so it is not that it can't find /test.txt.

Now I don't know the details, I can only guess, but in both cases (less without any redirection and less with the 1< redirection above) I believe that less detects that it isn't being called with stdin redirected from a pipe or file (the usual ways of call less) and so that then it looks to the command line arguments of less itself to find a file to load and display, and since you haven't passed a file name to less itself, that's when it prints "Missing filename", meaning "Missing filename argument (and no stdin to display)"

Author

Commented:
@noci:

In your case the shell (less is not running....)
The shell parser had created a "simple command"  less 1< /text.txt
During opening of the /test.txt file  the shell finds it cannot find the file.
Then it doesn't even try do the exec().

I already said it before, but in my example, the file /test.txt is an existing file with contents. So the shell should at least find the file because it's an existing file. So this can not be the correct answer. I didn't read the post of mccarl yet, but I'm gonna do this now.

Author

Commented:
@mccarl: Ah you've already noticed the same (sharp of you):

I will weigh in here because I see that last one differently... try this, just type "less" into the command line. You should get the same thing, so it is not that it can't find /test.txt.

However, also try this:

less 1< /test.txt       (with /test.txt being an existing file with contents)

Is in such a case "test.txt" no argument of less? The result is also "Missing filename".
mccarlIT Business Systems Analyst / Software Developer
CERTIFIED EXPERT
Top Expert 2015

Commented:
Is in such a case "test.txt" no argument of less?
No, it's not an argument of less at all. It's an argument to the shell to perform a redirection, less does not see any command line arguments at all, in this case. Just like running the plain "less" command.

Author

Commented:
Thanks! So to be sure, in summary:

I believe that less detects that it isn't being called with stdin redirected from a pipe or file (the usual ways of call less) and so that then it looks to the command line arguments of less itself to find a file to load and display,

We have to explain this:

1.    less 1< /test.txt       -> Missing filename
2.    less 0> /test.txt       -> read error

In the first case, less isn't being called with stdin redirected. So it looks to the arguments of less. There is no file, so the result is "Missing filename".

In the second case, less is being called with stdin redirect. The argument of less is "test.txt", so less starts to read test.txt. This results in a read error, because less doesn't have read permissions for test.txt.

Is this summary correct?
mccarlIT Business Systems Analyst / Software Developer
CERTIFIED EXPERT
Top Expert 2015

Commented:
Is this summary correct?
First case yes, second case no!

Again, don't know why this isn't obvious now, but less is still not called with any arguments. The 0> /test.txt is again an argument to the shell only. In this case, while attempting to detect if STDIN will provide it input, less attempts to read from FD 0 but since we've redirected 0 as a file mode W, the read fails with Read Error. It would be wrong to use the the term "file permissions" as that has a different usage. The user may permissions on the file to read and write, but because it is only opened in WRITE mode, the read fails.

Author

Commented:
Thanks for correcting me about using the word "permission". I have to see "mode" indeed. It's good for me to realize this.

And the arguments were not obvious yet, because of

and so that then it looks to the command line arguments of less itself to find a file to load and display, and since you have passed a file name to less itself

From this I thought it's about the arguments of less, but actually you meant the arguments of the shell here? Or we're just talking about different "arguments"?
mccarlIT Business Systems Analyst / Software Developer
CERTIFIED EXPERT
Top Expert 2015

Commented:
Whoops, no just a typo on my behalf, I meant...
and so that then it looks to the command line arguments of less itself to find a file to load and display, and since you haven't passed a file name to less itself

So the last two example command lines, that we are now discussing, have NO arguments to the less command itself, just shell redirection arguments.

Author

Commented:
Ah thanks! Then it's clear! :) Can you also correct it in your first post:

https://www.experts-exchange.com/questions/29121598/Why-less-0-test-txt-doesn't-output-Missing-filename-output-redirection.html#a42705079

Then I can mark that post as the correct answer.