Using netcat/cat in a background shell script (How to avoid Stopped (tty input)? ) - shell

Abstract: How to run an interactive task in background?
Details: I am trying to run this simple script under ash shell (Busybox) as a background task.
myscript.sh&
However the script stops immediately...
[1]+ Stopped (tty input) myscript.sh
The myscript.sh contents... (only the relvant part, other then that I trap SIGINT, SIGHUP etc)
#!/bin/sh
catpid=0
START_COPY()
{
cat /dev/charfile > /path/outfile &
catpid = $!
}
STOP_COPY()
{
kill catpid
}
netcat SOME_IP PORT | while read EVENT
do
case $EVENT in
start) START_COPY;;
stop) STOP_COPY;;
esac
done
From simple command line tests I found that bot cat and netcat try to read from tty.
Note that this netcat version does not have -e to supress tty.
Now what can be done to avoid myscript becoming stopped?
Things I have tried so for without any success:
1) netcat/cat ... < /dev/tty (or the output of tty)
2) Running the block containing cat and netcat in a subshell using (). This may work but then how to grab PID of cat?
Over to you experts...
The problem still exists.
A simple test for you all to try:
1) In one terminal run netcat -l -p 11111 (without &)
2) In another terminal run netcat localhost 11111 & (This should stop after a while with message Stopped (TTY input) )
How to avoid this?

you probably want netcat's "-d" option, which tells it not to read from STDIN.

I can confirm that -d will help netcat run in the background.
I was seeing the same issue with:
nc -ulk 60001 | nc -lk 60002 &
Every time I queried the jobs, the pipe input would stop.
Changing the command to the following fixed it:
nc -ulkd 60001 | nc -lk 60002 &

Are you sure you've given your script as is or did you just type in a rough facsimile meant to illustrate the general idea? The script in your question has many errors which should prevent it from ever running correctly, which makes me wonder.
The spaces around the = in catpid=$! make the line not a valid variable assignment. If that was in your original script I am surprised you were not getting any errors.
The kill catpid line should fail because the literal word catpid is not a valid job id. You probably want kill "$catpid".
As for your actual question:
cat should be reading from /dev/charfile and not from stdin or anywhere else. Are you sure it was attempting to read tty input?
Have you tried redirecting netcat's input like netcat < /dev/null if you don't need netcat to read anything?

I have to use a netcat that doesn't have the -d option.
"echo -n | netcat ... &" seems to be an effective workaround: i.e. close the standard input to netcat immediately if you don't need to use it.

As it was not yet really answered, if using Busybox and -d option is not available, the following command will keep netcat "alive" when sent to background:
tail -f /dev/null | netcat ...
netcat < /dev/null and echo -n | netcat did not work for me.

Combining screen and disown-ing process work for me, as '-d' option is not a valid anymore for netcat. Tried redirecting like nc </dev/null but session ends prematurely (as I need -q 1 to make sure nc process stop as file transfer finished)
Setup Receiver side first,
on Receiver side, screen keep stdin for netcat so it won't terminated
EDIT: I was wrong, you need to enter command INSIDE screen. You'll end with no file saved, or weird binary thing flow in your terminal while attach to screen, if you redirecting nc inline of screen command. (Example, this is THE WRONG WAY: screen nc -l -p <listen port> -q 1 > /path/to/yourfile.bin)
Open screen , then press return/Enter on welcome message. new blank shell will appear (you're inside screen now)
type command: nc -l -p 1234 > /path/to/yourfile.bin
then, press CTRL + a , then press d to detach screen.
on Sender sides, disown process, quit 1s after reaching EOF
cat /path/to/yourfile.bin | nc -q1 100.10.10.10 1234 & disown

Related

Why does this command not take input from file inspite of rediection?

On executing, the cisco anyconnect VPN client takes the VPN IP, password, and some other inputs from the terminal. However, instead of typing it every time, I wrote down the values in a file and tried to redirect the file into the vpn client command.
/opt/cisco/anyconnect/bin/vpn < vpndetails.txt
However, it seems that the command ignores the file redirection and still prompts for input. How is it possible? Does the code read from some other file-descriptor (not 0) and still reads it from the terminal? Is it possible?
Note: I know it isn't a good practice to store your passwords in a file, but I don't care for now.
The question "Is it possible" has the answer "yes".
The code for the anyconnect vpn probably reads /dev/tty, as explained in the comments by Chepner e.a.As a fun exercise, try this script:
#! /bin/sh
read -p "STDIN> " a
read -p "TERMINAL> " b < /dev/tty
read -p "STDIN> " c
echo "Read $a and $c from stdio and $b from the terminal"
and, for example, ls / | bash this_script.sh.
However, if you wish to use Cisco Autoconnect without passwords, you should investigate the Always On with Trusted Network detection feature and user certificates.
Writing to /dev/tty in the hope that it will be picked-up by the script does not work:
ljm#verlaine[tmp]$ ls | bash test.sh &
[3] 10558
ljm#verlaine[tmp]$ echo 'plop' > /dev/tty
plop
[3]+ Stopped ls | bash test.sh
ljm#verlaine[tmp]$ fg
ls | bash test.sh
(a loose enter is given)
Read a_file and b_file from stdio and from the terminal

How can I terminate netcat so my script can loop again?

I'm running a bash script that goes through the list of my remote server IPs, connects via netcat (telnet) for each line, and runs a few commands.
The problem is I can't seem to figure out how to terminate netcat so the script can loop to the next IP in the list.
Here's the relevant bit:
#!/bin/bash
while ISF= read -r line;do
(
sleep 3
printf 'command1'
sleep 3
printf 'command2'
sleep 3
) | nc $line
done < ~/servers.txt
The remote servers don't send an EOF, so is there something I can echo or printf at netcat to terminate netcat so the script can loop through again? I would really rather not do a -w flag for a timeout, because I have quite a few servers I need to do this on, and a timeout would make it take much longer.
Specify a timeout after which nc will exit if it receives no further input, either from the remote end or via standard input.
... | nc "$line" -w 10 # Choose a value for -w as appropriate
Depends on your version of netcat, but -c should do what your looking for. From the usage statement of gnu netcat (which is likely what you're running on Ubuntu):
-c, --close close connection on EOF from stdin

Handling input from script piped to netcat

I have a system that handles incoming emails to send them to a blackbox application at my job. The high level script is maintained by inittab to always run and runs a child script to do the actual work with this command:
$SCRIPT | nc -l -p $PORT
The script itself reads from a named pipe, does a bit of parsing and processing of the data before calling echo to shuffle the data back through netcat to the process connected on $PORT.
What I need is some method to handle incoming data from the far end of my pipe. When I make a request within the application to close the connection it sends back a string (I can define it to whatever I want) and waits for my script to close the pipe. I currently am struggling to understand how I can add in the functionality to read incoming data from the other end; verify it is the command to close the pipe, and then exit the script.
My script (in a nutshell) looks like this:
while true ; do
email_input="`cat "$pipe"`"
if [[ $email_input =~ .*escape_queue.* ]] ; then
break;
fi
echo "`parse`"
done
I'm open to the possibility of having to alter the program flow, I just can't wrap my head around how I would be able to read the data incoming asynchronously since the script blocks on cat $pipe until a new email is received to process.
If its not clear, I'm at a novice level with bash scripting and am always open to suggestions for improvement.
UPDATE
I've changed my script call to
$SCRIPT | nc -l -p $PORT > $nc_data
and within the script itself
netcat_response="`cat "$nc_data"`";
if [[ "$netcat_response" =~ "exit" ]] ; then
cat /dev/null > $nc_data
break;
fi
At this point the script terminates once a new message is piped into the fifo. This means that I will always lose 1 message as it gets read by the script and then the script terminates. The script still blocks on the cat until something is read. Worst case scenario this will have to do.
You can have nc quit after a certain time from the EOF of stdin.
$SCRIPT | nc -l -q 5 -p $PORT > $nc_data
-q being the option to quit after a certain amount of seconds.

Netcat not Working

I'm just beginning to work with bash scripts and I've tried to get a simple pipe to work:
#!/bin/sh
mkfifo apipe
cat apipe | nc -l $1 | /home/matt/testprogram > apipe
Given that the port number works and the program works as I want it to, what could be making this script mess up?
My program is supposed to print some text as well as take in some user input using fgets. When I run my shell script, I want it to act like as if I was just running the program normally. When I run it I just get it blanking out and not doing anything, and I have to break it with ctrl+C.
I type into the terminal something like:
sh testnc.sh 2342
Thanks for any advice
You are using NC wrong. nc -l $1 is listening for an external connection on that port. So you could run something like this:
host 1:
nc -l <port> | /home/matt/testprogram
host 2:
cat files | nc <host1> <port>
But the usage that you are doing makes no sense.

shell: how to make tail of a file running in background

I want to run a few tasks in shell.
tail a file into a new file: for example: tail -f debug|tee -a test.log
at the same time, run other tasks.
My question is: how to make the command tail -f debug|tee -a test.log run in background, so that I can run other tasks then in shell script?
You don't need tee at all for this, just use the shell's built-in append operator:
tail -f debug >> test.log &
The trailing & works as normal in the shell. You only need tee to send the output to a file as well as standard out, which if you have it in the background probably isn't what you want.
Normally you just use an ampersand after the command if you want to background something.
tail -f debug|tee -a test.log &
Then you can bring it back to the foreground later by typing fg. Did this answer your question or have I missed what you were asking?
The simple way to do this is:
screen -R -D
tail -f debug|tee -a test.log
Ctrl-A c
ps ax |grep tail
Ctrl-A [Backspace]
...
Ctrl-A [Spacebar]
screen lets you run multiple terminal sessions on one terminal connection. You switch back and forth with Ctrl-A [Backspace]|[Space]. To create another separate shell Ctrl-A c
A major benefit of screen is that if the terminal session disconnects, it keeps everything runnning. Just close the terminal window or disconnect ssh, go to another computer, log in and run screen -R -D to reconnect to everything which is still running.
If you only occasionally need this, just run tail, type Ctrl-Z, run a command, then fg %1 to bring the tail process back into the foreground, or bg %1 to make it run in the background permanently. If you do use Ctrl-Z, then the jobs command shows all of your detached jobs.

Resources