Input redirection (as in cat < file
) means the shell is opening the input file and writing its contents to the standard input of another process. Passing the file as an argument (as you do when running cat file
) means the program you are using (e.g. cat
) needs to open the file itself and read the contents.
Basically, command file
passes a file to command
while command < file
passes the contents of a file to command
. Yes, in cases like cat file
vs cat < file
there is no easily perceived difference in outcome, but but the two work in different ways.
To understand the difference, think of a young child and an adult. Both of them can drink water. However, the adult can open the tap and fill a glass (open the file and read its contents) while the child needs the water to be given to it directly (it can't open the file and can only process its contents).
Some programs, like cat
, are capable of taking a filename as input and then opening the file and doing their thing on it. That's why cat file
works. Other programs, however, don't have any knowledge of what files are or how to use them. All they know about is input streams (like the file's contents). For example, tr
:
$ cat file
foo
$ cat file | tr 'o' 'b' ## tr can read a stream
fbb
$ tr 'o' 'b' file ## tr can't deal with files
tr: extra operand ‘file’
Try 'tr --help' for more information.
$ tr 'o' 'b' < file ## input redirection!
fbb
Another example is ls
which can deal with files just fine, but ignores input streams:
$ ls
file1 file2
$ ls file1 ## lists only file1: ls takes file names as arguments
file1
$ ls < file1 ## ls ignores its standard input, this is the same as ls alone
file1 file2
Other programs can't deal with streams and instead require files:
$ rm < file ## fails, rm needs a file
rm: missing operand
Try 'rm --help' for more information.
$ rm file ## works, file is deleted
Some programs can deal with both opening files and reading input streams but behave in different ways with each. For example, wc
which, when given a file to open, prints the name of the file as well as the number of lines, words and characters:
$ wc file
1 1 4 file
But, if we just give it a stream, it has no way of knowing that this is coming from a specific file so no file name is printed:
$ wc < file
1 1 4
The md5sum
command behaves similarly:
$ md5sum file
17fd54512c91e3cd0f70fbaaa9a94d0d file
$ md5sum < file
17fd54512c91e3cd0f70fbaaa9a94d0d -
Note that in the first case the file name file
is shown while, in the second, "filename" is -
: standard input.
Now, if you want more gritty details, you can use strace
to see exactly what's going on:
strace -e trace=open,close,read,write wc file 2>strace1.txt
and
strace -e trace=open,close,read,write wc < file 2>strace2.txt
Those will have all the details of all open()
, close()
and read()
operations run by the process. What you want to see is that strace1.txt
(when the file was passed as an argument and not with input redirection) contains these lines:
open("file", O_RDONLY) = 3
read(3, "foo\n", 16384) = 4
Those mean that the file file
was opened and attached to the file descriptor 3
. Then, the string foo\n
was read from 3
. The equivalent part of the strace
output when using input redirection is:
read(0, "foo\n", 16384) = 4
There is no corresponding open()
call, instead the string foo\n
is being read from 0
, the standard input1.
1 By default, 0
is standard input, 1
is standard output and 2
is standard error. This, by the way, is why file
was opened as 3
, that was the next available one.
Your issue is that you need to encapsulate your path with quotes. It may look that you already are, but I guess you are getting confused by the number of "string in a string" you have.
Starting with your JSON, you are passing the value of the shell_cmd
key to your program which is:
gnome-terminal -- bash -c '${file_path}/${file_base_name}; read -sn 1'
That command is starting the gnome-terminal
application and asking it to run the following command on startup:
bash -c '${file_path}/${file_base_name}; read -sn 1'
That command, in turn, is executing bash
and telling it to run the following command - Take note of the non-existing quotes:
${file_path}/${file_base_name}; read -sn 1
Before running, that command will replace the variable with their appropriate value before being executed, and according to the error message you showed, the command is becoming the following:
/home/dr_insult/COMPUTER PROGRAMS/DATA STRUCTURES & ALGORITHMS/Stacks & Queues/; read -sn 1
Finally, what is happening, in this case, is that bash is parsing that command by splitting it on the &
character as it thinks it should run several commands in the backgrounds like so:
# This first command, for example, is attempting to run a script named
# /home/dr_insult/COMPUTER while passing two parameters
# "PROGRAMS/DATA" and "STRUCTURES" and attempting to put it in the background
/home/dr_insult/COMPUTER PROGRAMS/DATA STRUCTURES &
ALGORITHMS/Stacks &
Queues/
read -sn 1
All of those paths don't exist in your system, which it raising those errors you see.
What you need to do is to quote your that command in order to tell bash to treat all that string as a single path.
So change the value of the shell_cmd
key to the following (You will need to escape the double quotes so your JSON stays valid)
"gnome-terminal -- bash -c '\"${file_path}/${file_base_name}\"; read -sn 1'"
Best Answer
It's possible your terminal is not recognizing the window size correctly. I found a related question in U&L Stackexchange, and someone suggested the below way of checking whether this is what's going on:
Type
If the output is not:
You can use
to activate. To deactivate:
shopt -u checkwinsize