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
Related
I have some files to process by redirecting them to standard input, but bash complains about the wildcards.
someprogram < data/*
The bash error is bash: data/*: ambiguous redirect, Is there any work arounds to accomplish this instead of using cat to read the files and pipe the contents to the program.
No, this is not possible without using cat. Bash will open only a single file as stdin for a command. Btw, the is a useful use of cat :)
cat * | cmd
is the way to go here.
I have a command command that takes an input file as argument. Is there a way to call command without actually creating a file?
I would like to achieve the following behavior
$ echo "content" > tempfile
$ command tempfile
$ rm tempfile
if possible:
as a one-liner,
without creating a file,
using either a bash (or sh) feature or a "well-known" command (as standard as xargs)
It feels like there must be an easy way to do it but I can't find it.
Just use a process substitution.
command <(echo "content")
Bash will create a FIFO or other type of temporary file in /dev for the standard output of whatever happens in the process. For example:
$ echo <(echo hi)
/dev/fd/63
I have a command that I need to use repeatedly within a shell script. This is command contains a pipe and the output of the whole command will be piped to other commands.
e.g. Let's say for simplicity sake the command is ls | tee. Then I might pipe it to other commands, says ls | tee | someprogram or ls | tee | anotherprogram.
So naturally I'll want to keep ls | tee is a variable. The problem is that I can't seem to execute a variable with a pipe in it.
#!/bin/sh
TEST="ls | tee"
$TEST
Gives the following output
ls: cannot access |: No such file or directory
ls: cannot access tee: No such file or directory
How do I execute a variable like $TEST above, whist being able to pipe the output to other commands?
The short answer is eval.
eval $TEST somefile
eval $TEST otherfile | more
However, you need to be aware that eval means problems with quoting special characters and blanks and the like. If everything is simple (TEST="ls -l | tee"), then it is easy. If you have spaces in arguments or shell metacharacters, then it is hard — very hard — to do it right. At that point, you'd be better off creating a function or separate shell script.
You might well be better off with a function or shell script even so.
If the string you eval comes from a user, you have to worry even more!
I'm trying to install RVM. There is a magical command line:
bash < <(curl -s https://rvm.io/install/rvm)
I know what bash and curl are. I know the first < is the I/O redirection. But what does <() syntax mean?
What's the difference between this command and
bash < `curl -s https://rvm.io/install/rvm`
?(the latter command doesn't work)
This is bash's process substitution.
The expression <(list) gets replaced by a file name, either a named FIFO or an entry under /dev/fd. So to actually redirect input from it, you have to use < <(list).
[edit; forgot to answer your second question]
The backticks are called "command substitution". Unlike process substitution, it is part of the POSIX shell specification (i.e., not a bash extension). The shell runs the command in the backticks and substitutes its output on the command line. So this would make sense:
cat < `echo /etc/termcap`
But this would not:
cat < `cat /etc/termcap`
The latter is similar to your example; it tries to use the (complex) output of a command as a file name from which to redirect standard input.
The others have already answered your question very nicely. I'll just add an example to build on them... 99% of the time when I personally use <(), it's to diff the output of two different commands in one shot. For instance,
diff <( some_command ) <( some_other_command )
The syntax for io redirection is
process < file
Hence you need whatever appears after the io redirect to be a filename.
The backtick expansion literally puts the results of the command into the command line. Thus,
`curl -s https://rvm.io/install/rvm`
expands to something like
#!/usr/bin/env bash ...
and the shell would be confused because it would see
bash < #...
instead of a filename.
the <() operator is process substitution, which spawns a new process to run the command within the (..). A new file or pipe is created that will capture the result. The fact that the arrow is pointing left <() instead of >() means that the output from the inner process will be written to the file, which can be read by the process.
In your case, bash < <(...) will be seen as something like bash < /dev/fd/100
If you actually want to see what is going on, run
echo <(curl -s https://rvm.io/install/rvm)
It is called Process Substitution.
The standard way to capture command output in Bourne shell is to use the $() syntax:
output=$(mycommand)
For commands that have a lot of output, however, this requires the shell allocate memory for the whole thing as one long string. I'd prefer to find something that does the moral equivalent of the Unix C function popen, to get a new file descriptor I could read from:
newfd=popen(mycommand)
while read -u $newfd LINE; do
#process output
done
Is this even possible?
#!bash
ls | while read X
do
echo $X is a directory entry
done
Replace 'ls' with the command of your choice