Redirecting input of application (java) but still allowing stdin in BASH
I'm a little confused, I had this working yesterday, but it just stopped accepting the redirected stdin, almost m开发者_如何学编程agically.
set -m
mkfifo inputfifo
mkfifo inputfifo_helper
((while true; do cat inputfifo; done) > inputfifo_helper)&
trap "rm -f inputfifo inputfifo_helper java.pid; kill $!" EXIT
exec 3<&0
(cat <&3 > inputfifo)&
NOW=$(date +"%b-%d-%y-%T")
if ! [ -d "logs" ]; then
mkdir logs
fi
if [ -f "server.log" ]; then
mv server.log logs/server-$NOW.log
fi
java <inputfifo_helper -jar $SERVER_FILE & echo $! > java.pid && fg
This was running fine, I could echo things to inputfifo and the app got it, and I could type directly into it's console as well. It even worked through screen. Absolutely nothing code-wise has changed, but the redirected stdin has stopped working. I tried changing the file descriptor to 9, or even 127, but neither fixed it.
Am I forgetting something? Is there a specific reason it broke and no longer works?
(I'm using this instead of sending input to the screen itself because I start the screen detached and it refuses to receive input unless it's been attached to atleast once, I don't know if this is a bug or intended)
If you can keep your java program backgrounded, you may try to read from the controlling terminal /dev/tty
and write to inputfifo using a while-read loop.
# ...
java <inputfifo_helper -jar $SERVER_FILE & echo $! > java.pid
while IFS="" read -e -r -d $'\n' -p 'input> ' line; do
printf '%s\n' "${line}"
done </dev/tty >inputfifo
Its a hunch .. but could there be something else attached to fd 0?
On my linux I see this
$ ls -l /dev/fd/
total 0
lrwx------ 1 nhed nhed 64 Mar 24 19:15 0 -> /dev/pts/2
lrwx------ 1 nhed nhed 64 Mar 24 19:15 1 -> /dev/pts/2
lrwx------ 1 nhed nhed 64 Mar 24 19:15 2 -> /dev/pts/2
lr-x------ 1 nhed nhed 64 Mar 24 19:15 3 -> /proc/6338/fd
but on every subsequent ls the proc# pointed to by fd3 is different - I have no idea what this is about(maybe its tied to my prompt command), but fd 3 is taken, try fds #5-9
(and add ls -l /dev/fd/
at the top of the script for diagnostics)
Running a shortened version of your given code prints an I/O error message:
cat: stdin: Input/output error
A quick fix is to redirect stderr to /dev/null for this command.
On Mac OS X / FreeBSD you could also try using "cat -u" to disable output buffering (thus avoiding cat output buffering issues).
rm -v inputfifo inputfifo_helper
mkfifo inputfifo inputfifo_helper
(
((while true; do cat inputfifo; done) > inputfifo_helper) &
# use of "exec cat" terminates the cat process automatically after command completion
#((while true; do exec cat inputfifo; done) > inputfifo_helper) &
pid1=$!
exec 3<&0 # save stdin to fd 3
# following command prints: "cat: stdin: Input/output error"
#(exec cat <&3 >inputfifo) &
(exec cat <&3 >inputfifo 2>/dev/null) &
pid2=$!
# instead of: java <inputfifo_helper ...
(exec cat <inputfifo_helper) &
pid3=$!
echo $pid1,$pid2,$pid3
lsof -p $pid1,$pid2,$pid3
echo hello world > inputfifo
)
# show pids of cat commands
ps -U $(id -u) -axco pid,command | grep cat | nl # using ps on Mac OS X
Try using a single fifo and echo things to a r/w file descriptor. Use an ASCII NUL character to terminate your (lines of) input so that the read command continues reading until a NULL byte (or EOF).
rm -v inputfifo
mkfifo inputfifo
(
exec 0>&-
exec 3<>inputfifo # open fd 3 for reading and writing
echo "hello world 1" >&3
echo "hello world 2" >&3
printf '%s\n\000' "hello world 3" >&3
# replaces: java <inputfifo_helper ...
cat < <(IFS="" read -r -d '' <&3 lines && printf '%s' "$lines")
)
精彩评论