sending commands to a terminal from another one - unix

Let suppose you have a terminal (T1) open with 6350 pid.
Type :
echo "ls\n" > /proc/6350/fd/0 (writen in another terminal (T2)).
This writes ls and the line jump in T1 but does not execute it ? Why ?
I also tried using
cat|bash with echo "ls\n" > /proc/catPID/fd/0
but it is still not executed.
Any idea ?
Thanks,
Edited :
One possible trick :
mkfifo toto
$bash < toto
$echo "ls" > toto

First, if you want echo to intpret the \n as newline you have to call it with -e.
Secondly, what you want (hijack a terminal) is not (easy) doable, see unix.stackexchange. I would use screen on both sessions (one with the -x option).

Related

Using shebang in a spec file without it being a comment

I need to make a small wrapper script around the binary I'm packing in an RPM. That wrapper script needs to say "#!/bin/sh" at the top. But when I do that, the "#..." is treated like a comment. No, don't comment that.
Is there any way to use a predefined variable or escape sequence to make a shebang (on the first line)?
Here's my little code in the .spec file:
%build
echo #!/bin/bash > foobar
echo export LD_LIBRARY_PATH=/opt/foobar/foobar/lib >> foobar
echo /opt/foobar/lib/foobar >> foobar
echo exit $? >> foobar
... where the result of the 1st line in the %build cycle is simply "+ echo."
Must I take a different approach? If so, what approach?
Just coming back to my question.
Quote the hash-bang. 'nuff said.Thanks.

How to read 1 symbol in zsh?

I need to get exactly one character from console and not print it.
I've tried to use read -en 1 as I did using bash. But this doesn't work at all.
And vared doesn't seem to have such option.
How to read 1 symbol in zsh? (I'm using zsh v.4.3.11 and v.5.0.2)
read -sk
From the documentation:
-s
Don’t echo back characters if reading from the terminal. Currently does not work with the -q option.
-k [ num ]
Read only one (or num) characters. All are assigned to the first name, without word splitting. This flag is ignored when -q is present. Input is read from the terminal unless one of -u or -p is present. This option may also be used within zle widgets.
Note that despite the mnemonic ‘key’ this option does read full characters, which may consist of multiple bytes if the option MULTIBYTE is set.
If you want your script to be a bit more portable you can do something like this:
y=$(bash -c "read -n 1 c; echo \$c")
read reads from the terminal by default:
% date | read -sk1 "?Enter one char: "; echo $REPLY
Enter one char: X
Note above:
The output of date is discarded
The X is printed by the echo, not when the user enters it.
To read from a pipeline, use file descriptor 0:
% echo foobar | read -rk1 -u0; echo $REPLY
f
% echo $ZSH_VERSION
5.5.1
Try something like
read line
c=`echo $line | cut -c1`
echo $c

Why can't I read user input properly inside a UNIX while loop?

I'm using the bourne shell in UNIX, and am running into the following problem:
#!/bin/sh
while read line
do
echo $line
if [ $x = "true" ]
then
echo "something"
read choice
echo $choice
else
echo "something"
fi
done <file.txt
The problem I have here is that UNIX will not wait for user input in the read command - it just plows on through instead of waiting for what the user types in. How can I make unix wait for user input?
It is because you are asking the program to read from the file file.txt:
done <file.txt
Also looks like you have a typo here:
if [ $x = "true" ]
^^
which should be "$line". Also note the ", without them your program will break if the word read from the file has a space in it.
The redirection of standard input by the <file.txt at the end of while ... done <file.txt affects the whole while loop, including the read choice as well as the read line. It's not just failing to stop - it's consuming a line of your input file too.
Here's one way to solve the problem...
You can save the original standard input by using the somewhat obscure (even by shell standards):
exec 3<&0
which opens file descriptor 3 to refer to the original file descriptor 0, which is the original standard input. (File descriptors 0, 1 and 2 are standard input, output and error respectively.) And then you can redirect just the input of read choice to come from file descriptor 3 by doing read choice <&3.
Complete working script (I wasn't sure where x was supposed to come from, so I just bodged it to make it work):
#!/bin/sh
x=true # to make the example work
exec 3<&0
while read line
do
echo $line
if [ $x = "true" ]
then
echo "something"
read choice <&3
else
echo "something"
fi
done <file.txt
I don't do much shell scripting, but i think 'read choice' should be 'read $choice'

unix shell, getting exit code with piped child

Let's say I do this in a unix shell
$ some-script.sh | grep mytext
$ echo $?
this will give me the exit code of grep
but how can I get the exit code of some-script.sh
EDIT
Assume that the pipe operation is immutable. ie, I can not break it apart and run the two commands seperately
There are multiple solutions, it depends on what you want to do exactly.
The easiest and understandable way would be to send the output to a file, then grep for it after saving the exit code:
tmpfile=$(mktemp)
./some-script.sh > $tmpfile
retval=$?
grep mytext $tmpfile
rm tmpfile
A trick from the comp.unix.shell FAQ (#13) explains how using the pipeline in the Bourne shell should help accomplish what you want:
You need to use a trick to pass the exit codes to the main
shell. You can do it using a pipe(2). Instead of running
"cmd1", you run "cmd1; echo $?" and make sure $? makes it way
to the shell.
exec 3>&1
eval `
# now, inside the `...`, fd4 goes to the pipe
# whose other end is read and passed to eval;
# fd1 is the normal standard output preserved
# the line before with exec 3>&1
exec 4>&1 >&3 3>&-
{
cmd1 4>&-; echo "ec1=$?;" >&4
} | {
cmd2 4>&-; echo "ec2=$?;" >&4
} | cmd3
echo "ec3=$?;" >&4
If you're using bash:
PIPESTATUS
An array variable (see Arrays) containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command).
There is a utility named mispipe which is part of the moreutils package.
It does exactly that: mispipe some-script.sh 'grep mytext'
First approach, temporarly save exit status in some file. This cause you must create subshell using braces:
(your_script.sh.pl.others; echo $? >/tmp/myerr)|\ #subshell with exitcode saving
grep sh #next piped commands
exitcode=$(cat /tmp/myerr) #restore saved exitcode
echo $exitcode #and print them
another approach presented by Randy above, simplier code implementation:
some-script.sh | grep mytext
echo ${PIPESTATUS[0]} #print exitcode for first commands. tables are indexted from 0
its all. both works under bash (i know, bashizm). good luck :)
both approaches does not save temporarly pipe to physical file, only exit code.

`tee` command equivalent for *input*?

The unix tee command splits the standard input to stdout AND a file.
What I need is something that works the other way around, merging several inputs to one output - I need to concatenate the stdout of two (or more) commands.
Not sure what the semantics of this app should be - let's suppose each argument is a complete command.
Example:
> eet "echo 1" "echo 2" > file.txt
should generate a file that has contents
1
2
I tried
> echo 1 && echo 2 > zz.txt
It doesn't work.
Side note: I know I could just append the outputs of each command to the file, but I want to do this in one go (actually, I want to pipe the merged outputs to another program).
Also, I could roll my own, but I'm lazy whenever I can afford it :-)
Oh yeah, and it would be nice if it worked in Windows (although I guess any bash/linux-flavored solution works, via UnxUtils/msys/etc)
Try
( echo 1; echo 2 ) > file.txt
That spawn a subshell and executes the commands there
{ echo 1; echo 2; } > file.txt
is possible, too. That does not spawn a subshell (the semicolon after the last command is important)
I guess what you want is to run both commands in parallel, and pipe both outputs merged to another command.
I would do:
( echo 1 & echo 2 ) | cat
Where "echo 1" and "echo 2" are the commands generating the outputs and "cat" is the command that will receive the merged output.
echo 1 > zz.txt && echo 2 >> zz.txt
That should work. All you're really doing is running two commands after each other, where the first redirects to a file, and then, if that was successful, you run another command that appends its output to the end of the file you wrote in the first place.

Resources