cat only prints one file descriptor - cat

I am trying to understand how file descriptors work.
How come script2.sh below does not output the content of b.txt ?
$ cat a.txt
Hello
$ cat b.txt
World
$ cat script1.sh
cat a.txt b.txt
$ ./script1.sh
Hello
World
$ cat script2.sh
exec 19<a.txt
exec 20<b.txt
cat <&19 <&20
$ ./script2.sh
World

<&19 means "replace stdin with FD 19" and <&20 means "replace stdin with FD 20". These clobber each other. If you want to read two FDs, then do cat /dev/fd/19 /dev/fd/20 instead.

Related

Append in file a linux command

When doing
echo "some stuff" >> file.txt
I can append to my file some stuff
But when trying to do
echo ls >> file.txt
I append ls instead of listing all my items in the current path. How can I fix this? Sorry I'm new to linux
just redirect the ls output
ls >> file.txt
echo ls >> file.txt
This is interpreted as echo the term ls to file.txt. This isn't what you want.
>> redirects the output of a command, which can be ls.
So you could do:
ls >> file.txt

How to sed output of a command and not supress output

I have the example text stored in test.sh:
echo 'Hello world 123'
echo 'some other text'
With the following command in a bash script:
word123=$(./test.sh |sed -nr 's/Hello world (.*)/\1/p' )
This works correctly and outputs:
123
However, this does output
Hello world 123
some other text
Is there a way to capture the text in 123 and also output everything else in the file?
With Linux, bash and tee:
word123=$( ./test.sh | tee >&255 >(sed -nr 's/Hello world (.*)/\1/p') )
File descriptor 255 is a non-redirected copy of stdout.
See: What is the use of file descriptor 255 in bash process

Shell script - Output to both the terminal and a log file in a sub-shell

I have a few shell scripts that are intended to work together. The first script (script1.sh) calls the next script in a sub-shell. The second script (script2.sh) needs to "return" something for the first script to use. I need the last line that is echoed in the second script. However, when I use it this way, any output via echo in the second script does not get output to the terminal. I want all output from the first and second (and third, and fourth, ...) to be output to the terminal, but also written to a log file.
script1.sh:
#!/bin/sh
func_one() {
RESULT=$(./script2.sh | tail -1)
echo "RESULT: $RESULT"
}
func_one | tee log_file.log
script2.sh:
#!/bin/sh
echo "Hello"
echo "World!"
Attempt 1 output:
$ ./script1.sh
RESULT: World!
$
log_file.log contents:
RESULT: World!
If I try to redirect output in the second script, then it outputs to the terminal, but not to the log file:
script2.sh:
#!/bin/sh
echo "Hello" >&2
echo "World!" >&2
Attempt 2 output:
$ ./script1.sh
Hello
World!
RESULT:
log_file.log contents:
RESULT:
I also tried outputting to terminal and tee on the same line in script 1:
func_one >&2 | tee log_file.log
But that gives the same result as the first attempt.
What I would like is to have both output to the terminal AND written to the .log file: (if it was working correctly)
$ ./script1.sh
Hello
World!
RESULT: World!
$
log_file.log contents:
Hello
World!
RESULT: World!
How can I go about getting this result? Also, it would be preferred to NOT use bash, as a few of our machines we are going to be running this on do not have bash.
I've looked here:
How do I get both STDOUT and STDERR to go to the terminal and a log file?
but that didn't help in my case.
To get all the output of script2.sh sent to the terminal without interfering with the work of script1.sh, try this modification of script1.sh:
$ cat script1.sh
#!/bin/bash
func_one() {
RESULT=$(./script2.sh | tee >(cat >&2) | tail -1)
echo "RESULT: $RESULT"
}
func_one | tee log_file.log
Here, the first tee command makes sure that all script2.sh output appears, via stderr, on the terminal. To do this, process substitution is needed (and this, in turn, requires an upgrade from sh to bash).
The output is:
$ ./script1.sh
Hello
World!
RESULT: World!
Variation
This is the same as the above except that we don't touch stderr (you may want to reserve that errors). Here, we create an additional file descripter, 3, to duplicate stdout:
#!/bin/bash
exec 3>&1
func_one() {
RESULT=$(./script2.sh | tee >(cat >&3) | tail -1)
echo "RESULT: $RESULT"
}
func_one | tee log_file.log

How can bash be used to pipe stdout to a script AND write to terminal?

I would like to pipe the output of a job to a script to read in that stdout lines and complete actions and display the output on the terminal.
Right now, I have this..
ls | ./script.sh
This allows my script to be run on the output, but does not display the result of ls on the terminal.
I have tried this:
ls | tee ./script.sh
but this overwrites the contents of script.sh with the output from ls.
How can I show the output of "ls" on my terminal, and run the contents on script.sh over that input? Here is an example of what my script.sh looks like:
#!/bin/bash
while read line
do
echo line input
done
You can do:
ls | tee /dev/tty | ./script.sh
or, if you want to use exactly what stdout was before the piping, you can do
something like:
{ ls | tee /dev/fd/3 | ./script.sh ; } 3>&1 #(3 is an semi-arbirtrary choice of fd)

Print on terminal and into file simultaneously?

I have a shell script that greps some data.. I want to print the result into a file, but doing that prevents the result being displayed on the terminal. Is there a way that can both print the result on the screen and also write into a file.
Thanks in advance.
Pipe your output to the tee command.
Example:
[me#home]$ echo hello | tee out.txt
hello
[me#home]$ cat out.txt
hello
Note that the stdout of echo is printed out as well as written to the file specified by thr tee command.
Note you can add the -a flag to tee to append to the output file
[me#home]$ echo hello | tee out.txt
hello
[me#home]$ echo hello again | tee -a out.txt
hello again
[me#home]$ cat out.txt
hello
hello again
Does exactly your thing
http://linux.die.net/man/1/tee

Resources