This question already has answers here:
Useless use of cat?
(9 answers)
Piping and Redirection
(5 answers)
Closed 3 years ago.
What is the difference between the statement cat a.txt | wc and the statement wc < cat a.txt. In both cases, isn’t the output of cat a.txt being directed into wc?
Absolutely not. In your second case (wc < cat a.txt) you are invoking the command wc a.txt while connecting a file named cat to the standard input of the process.
It might seem confusing, but most shells allow you to redirect the input anywhere in the command line.
wc a.txt < cat
would be the same as (the arguably more confusing)
wc < cat a.txt
To redirect the output of a command to the input of another, you use the pipe character. To invoke a command with a file as its standard input, you use the chevrons.
Now, modern shells will let you type commands like this one:
wc <(cat a.txt)
This is called process substitution and is not exactly the same thing as either of the two methods you were asking about. In this case, the shell will invoke the process cat a.txt and "catch" its output in a file descriptor. Then, the shell will invoke the "main" command (wc) and pass a reference to that file descriptor as an argument, as if it were a file name. It enables a command that expects a simple file name to read the output of an ad hoc command.
Related
This question already has answers here:
Difference in pipe and file redirection - BASH
(3 answers)
What is a simple explanation for how pipes work in Bash?
(11 answers)
Piping and Redirection
(5 answers)
Closed 2 years ago.
Here is something I don't understand.
Why this works : echo "akka" | cat
But this does not produce "akka" on the console : echo "akka" > cat
And this does not even work : cat < echo "akka"
For me they should be the same. But these 3 commands seem different
You are confusing the differences between file redirection and piping.
The pipe symbol | is used to pass the output of one command into another command.
Meanwhile, < and > are used for file redirection.
These are very different operations.
Example 1:
echo "akka" | cat
The echo command has the output akka, and this is piped into the standard input of the cat command. The cat command writes to standard output, so in this case it prints akka. Of course, this is no different from doing simply:
echo "akka"
Example 2:
echo "akka" > cat
The echo command has the output akka. Using >, this output is then redirected into a file called cat. There is no output shown in the terminal in this case, since the output is placed into a file instead.
Example 3:
cat < echo "akka"
This is quite different from the first two. This runs the cat command, which reads from standard input. Using <, input is passed to the cat command from a file called echo. If no such files exists, then it will produce an error.
I have made a program that acts as a shell and for testing purposes, I try and use the < operator, but receive this error in my bash
the purpose is to take ls as an input and run it in my mock shell
Is there a specific reason I am receiving this error, could it be from my code?
the name of my program is rshell:
[xx#xx rshell]$ ./bin/rshell < ls
bash: ls: No such file or directory
The right-hand side of the input redirection operator < requires a filename. So the shell interprets "ls" in your example as a filename. You get an error because there is no such file.
If you want to pass the output of ls to your shell, use a pipe:
ls | ./bin/rshell
Or process substitution:
./bin/rshell < <(ls)
If you want to pass the text "ls" on standard input to your shell, use a here-string:
./bin/rshell <<< ls
The syntax you have, ./bin/rshell < ls, means "read from a file named 'ls'".
If you are trying to send the output of the ls command into /bin/rshell, you need to either pipeline it with a pipe:
ls | ./bin/rshell
or read from an anonymous filehandle:
./bin/rshell < <(ls)
Basically, > and < are for dealing with files (file i/o), and | is what you want for dealing with passing output from one command to another (command i/o); but, you can combine the two with anonymous filehandles using the <(command) syntax.
Inside of a shell script, you can do fancier things, such as storing the output of a command in a string variable, then using that string as input, parsing it up, and all kinds of fun stuff. First things first, though.
An excellent resource for learning all things bash is the Advanced Bash-Scripting Guide: http://www.tldp.org/LDP/abs/html/index.html
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I want to get the PID of bash and highlight it if it's in some textfile (assume it is). So when I'm typing this in my shell:
grep -o $(pidof bash) test.txt
it just works fine and gives me the desired output, the PID of bash.
Then why is this script not working:
#!/bin/bash
PID=$(grep -o $(pidof bash) test.txt)
echo $PID
I only get some lines with:
grep: xxx: file or directory not found
xxx are random numbers, but usually the last one is the one I'm looking for.
How do I achieve this and why is the above not working?
Has this something to do with creating a new process by the shell when calling grep in the script?
Thank you.
I don't have pidof, so I'm assuming that it's an equivalent to pgrep -v, printing a list of PIDs, one on each line, with a newline between them.
If that's so, consider this:
egrep -o "$(pgrep -v bash | tr '\n' '|')" test.txt
Assume that the output of pgrep -v bash is:
123
456
789
Your original code would do this:
egrep -o 123 456 789 test.txt
...thus, searching for 123 in a file named 456, in a file named 789, and in a file named test.txt.
Now, compare to what happens when you replace that whitespace with pipe symbols:
egrep -o "123|456|789" test.txt
...as executed by the pipeline suggested earlier in this question is exactly what you were looking for. (BTW, the quotes here are purely syntactic -- that is, they're for consumption by the shell when it's understanding how things are parsed, not passed to egrep).
That said, if you're looking for the current bash process, use either $$ (for the parent PID of the current shell) or $BASH_PID (for the current shell itself even if it's a subshell), rather than using so inexact a tool as pgrep or pidof.
When you run pidof inside your shell script, there are at least two instances of bash running, so it will return multiple numbers. The way grep is designed, it can only search for one pattern at a time so the first number is interpreted as a pattern and the other numbers are mistakenly interpreted as file or directory names.
I'm not sure which bash PID you care about, but one solution is to use something like grep, head, or tail to filter the output of pidof so you just get one number. Another solution is to use the special variable $$, which is the PID of bash instance that evaluates it.
In the future, you can debug this better for yourself. To debug, I would start by running this command inside your script to see exactly what arguments are being passed to grep:
echo grep -o $(pidof bash) test.txt
This question already has answers here:
How to pass command output as multiple arguments to another command
(5 answers)
Closed 5 years ago.
When I run the following Bash script, I would expect it to print Hello. Instead, it prints a blank line and exits.
echo 'Hello' | echo
Why doesn't piping output from echo to echo work?
echo prints all of its arguments. It does not read from stdin. So the second echo prints all of its arguments (none) and exits, ignoring the Hello on stdin.
For a program that reads its stdin and prints that to stdout, use cat:
$ echo Hello | cat
Hello
In this case the pipe you are using are more correctly known as anonymous pipes, because they have no name (there are also named pipes). Anonymous pipes only work between related processes, for example processes with the same parent.
Pipes are part of the IO system resulting from the C runtime-library. These streams are buffered (there is an exception) by default. Basically a pipe is just connecting the output buffer from one process to the input buffer of another.
The first three streams used (called file descriptors) are numbered 0, 1, and 2. The first, 0, is known as standard input, or stdin (the name used in C). By default this is connected to the keyboard, but it can be redirected either using the < symbol or the program name being on the right side of a pipe.
The second, 1, is known as standard output, or stdout. By default this is connected to the terminal screen, but can be redirected by using the > symbol or the program name being on the left side of a pipe.
So:
echo 'Hello' | echo
takes the standard output from echo and passes it to the standard input of echo. But echo does not read stdin! So nothing happens.
Filter programs process the filenames specified on the command-line. If no filenames are given then they read stdin. Examples include cat, grep, and sed, but not echo. For example:
echo 'Hello' | cat
will display 'Hello', and the cat is useless (it often is).
echo 'Hello' | cat file1
will ignore the output from echo and just display the contents of file1. Remember that stdin is only read if no filename is given.
What do you think this displays?
echo 'Hello' | cat < file1 file2
and why?
Finally, the third stream, 2, is called standard error, or stderr, and this one is unbuffered. It is ignored by pipes, because they only operate between stdin and stdout. However, you can redirect stderr to use stdout (see man dup2):
myprog 2>&1 | anotherprog
The 2>&1 means "redirect file descriptor 2 to the same place as fie descriptor 1".
The above is normal behaviour, however a program can override all that if it wants to. It could read from file descriptor 2, for example. I have omitted a lot of other detail, including other forms of redirection such as process substitution and here documents.
Piping can be done only for commands taking inputs from stdin. But echo does not takes from stdin. It will take input from argument and print it. So this wont work. Inorder to echo you can do something like echo $(echo 'hello')
It is because echo (both builtin and /bin/echo) don't read anything from stdin.
Use cat instead:
echo 'Hello' | cat
Hello
Or without pipes:
cat <<< 'Hello'
I have a compiled program which i run from the shell; as i run it, it asks me for an input file in stdin. I want to run that program in a bash loop, with predefined input file, such as
for i in $(seq 100); do
input.txt | ./myscript
done
but of course this won't work. How can I achieve that? I cannot edit the source code.
Try
for i in $(seq 100); do
./myscript < input.txt
done
Pipes (|) are inter-process. That is, they stream between processes. What you're looking for is file redirection (e.g. <, > etc.)
Redirection simply means capturing output from a file, command,
program, script, or even code block within a script and sending it as
input to another file, command, program, or script.
You may see cat used for this e.g. cat file | mycommand. Given the above, this usage is redundant and often the winner of a 'Useless use of cat' award.
You can use:
./myscript < input.txt
to send content of input.txt on stdin of myscript
Based on your comments, it looks like myscript prompts for a file name and you want to always respond with input.txt. Did you try this?
for i in $(seq 100); do
echo input.txt | ./myscript
done
You might want to just try this first:
echo input.txt | ./myscript
just in case.