Grep command Linux ordering of source string and target string - linux

Grep command syntax is as:
grep "literal_string" filename --> search from string in filename.
So I am assuming the order of is like this
-- keyword(grep) --> string to be searched --> filename/source string and command is interpreted from left to right.
My question is how the commands such as this got processed:
ps -ef | grep rman
Do the order is optional?
How grep is able to know that source is on left and not on right? Or I am missing something here.

When using Unix Pipes, most system commands will take the output from the previous command (to the left of the pipe ) and then pass the output onto the command to the right of the pipe.
The order is important when using grep with or without a pipe.
Thus
grep doberman /file/about/dogs
is the same as
cat /file/about/dogs | grep doberman
See Pipes on http://linuxcommand.org/lts0060.php for some more information.

As step further down from Kyle's answer regarding pipes is that most shell commands read their input from stdin and write their output to stdout. Now many of the commands will also allow you to specify a filename to read from or write too, or allow you to redirect a file to stdin as input and redirect the commands stdout to a file. But regardless how you specify what to read, the command process input from it's stdin and provides output on stdout (errors on stderr). stdin, stdout, and stderr are the designation of file descriptors 0, 1 & 2, respectively.
This basic function is what allows command to be piped together. Where a pipe (represented by the | character) does nothing more that take the stdout from the first command (on left) and direct it to the next commands stdin. As such, yes, the order is important.
Another point to remember is that each piped process is run in its own subshell. Put another way, each | will spawn another shell to run the following command in. This has implications if you are relying on the environment of one process for the next.
Hopefully, these answers will give you a better feel for what is taking place.

Related

Redirect output from subshell and processing through pipe at the same time

tl;dr: need a way to process (with grep) an output inside subshell AND redirect all original output to the main stdout/stderr at the same time. I am looking for shell-independent (!) way.
In detail
There is a proprietary binary which I want to grep for some value
The proprietary binary from time to time might be interactive to ask for a password (depends on the internal logic)
I want to grep the output of the binary AND want being able to enter the password it that is required to proceed further
So the script which is supposed to achieve my task might look like:
#!/bin/sh
user_id=... # some calculated value
list_actions_cmd="./proprietary-binary --actions ${user_id}"
action_item=$(${list_actions_cmd} | grep '^Main:')
Here proprietary-binary might ask for a password through stdin. Since subshell inside $() catches the all output, an end-user won't understand that the list_actions_cmd waits for input. What I want is either to show all output of list_action_cmd AND grepping at the same time or at least caught the keyword that now user will be asked for a password and let him know about that.
Currently what I figured out is to tee the output and grep there:
#!/bin/sh
user_id=... # some calculated value
list_actions_cmd="./proprietary-binary --actions ${user_id}"
$list_actions_cmd 2>&1 | tee /tmp/.proprietary-binary.log
action_item=$(grep "^Main" /tmp/.proprietary-binary.log)
But I wonder is there any elegant shell-independent (not limited to bash which is quite powerful) solution without any intermediate temporary file? Thanks.
What about duplicating output to stderr if executed in a terminal:
item=$(your_command | tee /dev/stderr | grep 'regexp')

How does 'ls' command work when it has multiple arguments?

How does the 'ls' command work in Linux/Unix?
So that's some reference.
But I was wondering how a command such as
ls -1 | grep 'myfile'
would be executed by the shell, i.e. when is exec called, when is fork called, when id dup called(if at all).
Also, how is this entire command parsed?
What does fork do
Fork is the primary (and historically, only) method of process creation on Unix-like operating systems.
What does exec do
In computing, exec is a functionality of an operating system that runs an executable file in the context of an already existing process
What does this mean
When you run a command (that is not built in like exit, cd), shell creates a child process using fork. This child process then uses exec executes the binary file for that command (e.g: /bin/ls)
What happens when during input/output redirecction
Every process is supplied with three streams standard input (STDIN), standard output (STDOUT) and standard error (STDERR). By default these streams are mapped to parent process's respective streams. Thus commands like wc or nano which reads from STDIN can be supplied with data from parent shell process's STDIN, and their output is captured by parent shell process and displayed.
However, when using redirection like
ls /tmp /abcd 1>out.log and 2>err.log
stdout is now mapped to a file output stream of out.log, similarly stderr is mapped to err.log. And the output is written to corresponding files.
PIPE chaining
ls -1 | grep 'myfile'
In shell PIPE | is used to chain the STDOUT of first command to STDIN of second command.
This means output of ls -1 (list of files and directories) is given as input to grep myfile which searches for lines containing "myfile" and prints to its STDOUT. The combined effect is to search filename containing char sequence "myfile"
I'm answering here specifically the textual question of the title,
How does 'ls' command work when it has multiple arguments?
...not addressing the question which came underneath. Was needing to check if a list of files was present in a directory and this question's phrasing was the closest to what I needed.
If you need to do this, either separate them with a space or wrap them in curly brackets with commas and no space as follows:
ls something.txt something_else.txt
or
ls {something.txt,something_else.txt}

Why more command cannot read stdin but from piped stdin?

I have doubt in more command. Normally, more cannot read from stdin, but using pipe it reads the content from stdin.
For example, While trying to execute more command to get the input from stdin, it is rejecting.
$ more [Enter]
Usage: more [options] file...
Options:
-d display help instead of ring bell
-f count logical, rather than screen lines
-l suppress pause after form feed
-p suppress scroll, clean screen and disblay text
-c suppress scroll, display text and clean line ends
-u suppress underlining
-s squeeze multiple blank lines into one
-NUM specify the number of lines per screenful
+NUM display file beginning from line number NUM
+/STRING display file beginning from search string match
-V output version information and exit
But, Here it is taking input from piped stdin.
$ cat file.txt
This is for testing purpose
$ cat file.txt | more
This is for testing purpose
I would like know how this is happening ( mean not reading from stdin but from piped stdin?
more discriminates on whether its standard input comes from a TTY or from elsewhere (pipe, regular file, etc.). As explained in the comments, if the input comes from a TTY, more refuses to run because it needs the TTY to read its command keystrokes. cat, on the other hand, is not interactive and doesn't deal with the TTY explicitly, so it can afford not to care whether its input is a TTY or other type of open file.
There are many other examples of Unix utilities behaving differently based on whether the standard input or output is a TTY. For example, ls formats its output in multiple columns, while ls | cat does not.

Program dumps data to stdout fast. Looking for way to write commands without getting flooded

Program is dumping to stdout and while I try to type new commands I can't see what I'm writing because it gets thrown along with the output. Is there a shell that separates commands and outputs? Or can I use two shells where I can run commands on one and make it dump to the stdout of another?
You can redirect the output of the program to another terminal window. For example:
program > /dev/pts/2 &
The style of terminal name may depend on how your system is organized.
There's 'more' to let you pageinate through output, and 'tee' which lets you split a programs output, so it goes to both stdout and to a file.
$ yourapp | more // show in page-sized chunks
$ yourapp | tee output.txt // flood to stdout, but also save a copy in output.txt
and best of all
$ yourapp | tee output.txt | more // pageinate + save copy
Either redirect standard output and error when you run the program, so it doesn't bother you:
./myprog >myprog.out 2>&1
or, alternatively, run a different terminal to do your work in. That leaves your program free to output whatever it likes to its terminal without bothering you.
Having said that, I'd still capture the information from the program to a file in case you have to go back and look at it.

How can I make Bash automatically pipe the output of every command to something like tee?

I use some magic in $PROMPT_COMMAND to automatically save every command I run to a database:
PROMPT_COMMAND='save_command "$(history 1)"'
where save_command is a more complicated function. It would be nice to save also the head/tail of the output of each command, but I can't think of a reasonable way to do this, other than manually prepending some sort of shell function to everything I type (and this becomes even more painful with complicated pipelines or boolean expressions). Basically, I just want the first and last 10 lines of whatever went to /dev/tty to get saved to a variable (or even a file) - is there any way to do this?
script(1) will probably get you started. It won't let you just record the first and last 10 lines, but you can do some post-processing on its output.
bash | tee /dev/tty ./bashout
This saves all stdout gets saved to bashout.
bash | tee /dev/tty | tail > ./bashout
The tail of stdout of every command gets written to bashout.
bash | tee /dev/tty | sed -e :a -e '10p;$q;N;11,$D;ba' > ./bashout
The first and last 10 lines of stdout of every command gets written to bashout.
These don't save the command, but if you modify your save_command to print the command to stdout, it will get in there.

Resources