The cat file | command
syntax is considered a Useless Use of Cat
. Of all your options, it takes a performance hit because it has to spawn another process in the kernel. However insignificant this may turn out to be in the big picture, it's overhead the other forms don't have. This has been covered on questions such as: Should I care about unnecessary cats?
Between the other two forms there are virtually no performance differences. STDIN is a special file node that the process has to open and read just like any other. Passing a file name instead of STDIN just makes it open a different file.
The difference would be in what features / flexibility you are looking for.
- Passing the file name to the program would mean the input file was seekable. This may or may not matter to the program but some operations can be sped up if the stream is seekable.
- Knowing the actual input file allows your program to potentially write to it. For example
sed -i
for in-place editing. (Note: since this has to create a new file behind the scenes it's not a performance gain over other redirects but it is a convenience step.)
- Using shell redirects gives you the ability to concatenate multiple files or even use process redirection.
sed [exp] < file1 file2
or even sed [exp] < <(grep command)
. Details of this use case can be found on this question: Process substitution and pipe
It's the fd to the master side of the pseudo-terminal in the terminal emulator that you want to monitor if you want to see what's displayed on it. That master fd is what simulates the wire that goes to a real terminal. What xterm
writes on it is the characters generated from the key you press. What it reads from it is what it displays.
For instance, on Linux:
$ lsof -ac xterm /dev/ptmx
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
xterm 15173 chazelas 4u CHR 5,2 0t0 2131 /dev/ptmx
And then run for instance:
stty -echo -opost
strace -e read -e read=4 -p15173 2>&1 | stdbuf -o0 sh -c '
grep "^ |" | cut -b11-60 | tr -d " " | xxd -r -p'
Of course, it works better if you run that in a terminal of same type and size as the one you're trying to monitor. You can get the size with:
stty size < /dev/pts/that-terminal
That dumps what is read by xterm
from the master side of the terminal, so what is displayed there, including the local echo
of what is being typed.
The -e read=4
above is for strace
to output a hexdump of what xterm
reads on its fd 4. The rest of the command is to convert that to the actual characters. I tried peekfd -n -8 15173 4
but for some reason that only gave what was being written.
We're using -opost
to disable any post-processing in our monitoring terminal, so that everything xxd
writes to the slave side makes it unchanged to our master side, so that our monitoring xterm
gets the same thing as the monitored one. -echo
is so that if the application in the monitored terminal sends an escape sequence that requests an answer from the terminal (such as those that request the cursor position or the terminal type or window title), that will make its way to our monitoring xterm
and our xterm
will reply as well. We don't want a local echo of that.
You could also monitor what is being typed by tracing the write
system calls to that same fd (replace read
with write
above). Note that upon pressing Enter, the terminal emulator sends a CR character, not LF. Also, since we're tracing on the master side, if the user types a<Backspace>b
, we'll see all 3 keystrokes even if the terminal device is in canonical mode.
As to why yours doesn't work:
tee /dev/pts/user_pts </dev/pts/user_pts
Reading from the terminal device is reading the user input, and writing to it is to display it to the user.
You're telling tee
to read from the terminal device. So what it reads (the user input) won't be read
by the application(s) running in the terminal (and vis versa, tee
and that application
will fight for the terminal input). Writing to the terminal device, is for display there, it is not for putting it back there as input. When you do
echo test
(with echo
's stdout being the terminal), it is not the same thing as if you had typed test
.
There is an ioctl
(TIOCSTI
) to put characters back as input, but even that would not really work because you could put it back after the application as already read some more, so it would change the order the application is reading input, and any way, that would mean you would read it over and over again.
Best Answer
cat /dev/null > file.txt
is a useless use of cat.Basically
cat /dev/null
simply results incat
outputting nothing. Yes it works, but it's frowned upon by many because it results in invoking an external process that is not necessary.It's one of those things that is common simply because it's common.
Using just
> file.txt
will work on most shells, but it's not completely portable. If you want completely portable, the following are good alternatives:Both
:
andtrue
output no data, and are shell builtins (whereascat
is an external utility), thus they are lighter and more 'proper'.Update:
As tylerl mentioned in his comment, there is also the
>| file.txt
syntax.Most shells have a setting which will prevent them from truncating an existing file via
>
. You must use>|
instead. This is to prevent human error when you really meant to append with>>
. You can turn the behavior on withset -C
.So with this, I think the simplest, most proper, and portable method of truncating a file would be: