Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.debian.user > #269804 > unrolled thread
| Started by | Greg Wooledge <greg@wooledge.org> |
|---|---|
| First post | 2024-06-01 16:10 +0200 |
| Last post | 2024-06-03 18:00 +0200 |
| Articles | 2 — 2 participants |
Back to article view | Back to linux.debian.user
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: advanced scripting problems - or wrong approach? Greg Wooledge <greg@wooledge.org> - 2024-06-01 16:10 +0200
Re: advanced scripting problems - or wrong approach? David Christensen <dpchrist@holgerdanske.com> - 2024-06-03 18:00 +0200
| From | Greg Wooledge <greg@wooledge.org> |
|---|---|
| Date | 2024-06-01 16:10 +0200 |
| Subject | Re: advanced scripting problems - or wrong approach? |
| Message-ID | <IKxAJ-hssl-1@gated-at.bofh.it> |
On Sat, Jun 01, 2024 at 09:20:59AM +0200, DdB wrote:
> > #!/bin/bash -e
> >
> > coproc { bash; }
> > exec 5<&${COPROC[0]} 6>&${COPROC[1]}
> > fd=5
> >
> > echo "ls" >&6
> > while IFS= read -ru $fd line
> > do
> > printf '%s\n' "$line"
> > done
> >
> > printf "%s\n" "sleep 3;exit" >&6
> > while IFS= read -ru $fd line
> > do
> > printf '%s\n' "$line"
> > done
> >
> > exec 5<&- 6>&-
> >
> > wait
> > echo waited, done
>
> i get the output from ls, but then the thing is hanging indefinitely,
> apparently not reaching the exit line. :(
Your first while loop never terminates. "while read ..." continues
running until read returns a nonzero exit status, either due to an
error or EOF. Your coproc never returns EOF, so the "while read"
loop just keeps waiting for the next line of output from ls.
If you're going to communicate with a long-running process that can
return multiple lines of output per line of input, then you have
three choices:
1) Arrange for some way to communicate how many lines, or bytes,
of output are going to be given.
2) Send a terminator line (or byte sequence) of some kind that
indicates "end of current data set".
3) Give up and assume the end of the data set after a certain amount
of time has elapsed with no new output arriving. (This is usually
not the best choice.)
These same design issues occur in any kind of network communication, too.
Imagine an IMAP client or something, which holds open a network connection
to its IMAP server. The client asks for the body of an email message,
but needs to keep the connection open afterward so that it can ask for
more things later. The server has to be able to send the message back
without closing the connection at the end. Therefore, the IMAP protocol
needs some way to "encapsulate" each server response, so the client
knows when it has received the full message.
[toc] | [next] | [standalone]
| From | David Christensen <dpchrist@holgerdanske.com> |
|---|---|
| Date | 2024-06-03 18:00 +0200 |
| Message-ID | <ILigh-li3-1@gated-at.bofh.it> |
| In reply to | #269804 |
On 6/2/24 21:35, DdB wrote:
> Am 02.06.2024 um 02:41 schrieb DdB:
>> Will share my findings, once i made more progress...
>
> Here is what i've got before utilizing it:
>
>
>> datakanja@PBuster-NFox:/mnt/tmp$ cat test
>> #!/bin/bash -e
>> # testing usefulness of coprocess to control host and backup machine from a single script.
>> # beware: do not use subprocesses or pipes, as that will confuse the pipes setup by coproc!
>> # At this point, this interface may not be very flexible
>> # but trying to follow best practices for using coproc in bash scripts
>> # todo (deferred): how to handle stderr inside coproc?
>> # todo (deferred): what, if coproc dies unexpectedly?
>>
>> # setting up the coprocess:
>> stdout_to_ssh_stdin=5 # arbitrary choice outside the range of used file desciptors
>> stdin_from_ssh_stdout=6
>>
>> coproc SSH { bash; } # for testing purposes, i refrain from really involving ssh just yet and replace it with bash:
>>
>> # save filedescriptors by duplicating them:
>> eval "exec ${stdin_from_ssh_stdout}<&${SSH[0]} ${stdout_to_ssh_stdin}>&${SSH[1]}"
>> echo The PID of the coproc is: $SSH_PID # possibly useful for inspection
>>
>> unique_eof_delimirer="<EOF>"
>> line=""
>> # collect the output available and print it locally (synchonous):
>> function print-immediate-output () {
>> while IFS= read -r -u "${stdin_from_ssh_stdout}" line
>> do
>> if [[ "${line:0-5:5}" == "$unique_eof_delimirer" ]] # currently, the length is fixed
>> then
>> line="${line%<EOF>}"
>> if [[ ! -z $line ]]
>> then
>> printf '%s\n' "$line"
>> fi
>> break
>> fi
>> printf '%s\n' "$line"
>> done
>> }
>>
>> # send a single command via ssh and print output locally
>> function send-single-ssh-command () {
>> printf '%s\n' "$@" >&"${stdout_to_ssh_stdin}"
>> printf '%s\n' "echo '"$unique_eof_delimirer"'" >&"${stdout_to_ssh_stdin}"
>> print-immediate-output
>> }
>>
>>
>> send-single-ssh-command "find . -maxdepth 1 -name [a-z]\*" # more or less a standard command, that succeeds
>> send-single-ssh-command "ls nothin" # more or less a standard command, that fails
>>
>> # tearing down the coprocess:
>> printf "%s\n" "exit" >&"${stdout_to_ssh_stdin}" # not interested in any more output (probably none)
>> wait
>> # Descriptors must be closed to prevent leaking.
>> eval "exec ${stdin_from_ssh_stdout}<&- ${stdout_to_ssh_stdin}>-"
>>
>> echo "waited for the coproc to end gracefully, done"
>>
>> datakanja@PBuster-NFox:/mnt/tmp$ ./test
>> The PID of the coproc is: 28154
>> ./test
>> ./out
>> ls: Zugriff auf 'nothin' nicht möglich: Datei oder Verzeichnis nicht gefunden
>> waited for the coproc to end gracefully, done
>> datakanja@PBuster-NFox:/mnt/tmp$
"test" is both a program and a shell builtin. I suggest that you pick
another, non-keyword, name for your script.
I suggest adding the Bash option "-u' (nounset).
Your file descriptor duplication, redirection, etc., seems overly
complex. Would not it be easier to use the coproc handles directly?
2024-06-03 08:49:41 dpchrist@laalaa ~/sandbox/bash
$ nl coproc-demo
1 #!/usr/bin/env bash
2 # $Id: coproc-demo,v 1.3 2024/06/03 15:49:36 dpchrist Exp $
3 set -e
4 set -u
5 coproc COPROC { bash ; }
6 echo 'echo "hello, world!"' >&"${COPROC[1]}"
7 read -r reply <&"${COPROC[0]}"
8 echo $reply
9 echo "exit" >&"${COPROC[1]}"
10 wait $COPROC_PID
2024-06-03 08:49:44 dpchrist@laalaa ~/sandbox/bash
$ bash -x coproc-demo
+ set -e
+ set -u
+ echo 'echo "hello, world!"'
+ bash
+ read -r reply
+ echo hello, 'world!'
hello, world!
+ echo exit
+ wait 4229
David
[toc] | [prev] | [standalone]
Back to top | Article view | linux.debian.user
csiph-web