将命令发送到 GNU 屏幕

发布于 2024-11-08 05:55:40 字数 215 浏览 3 评论 0原文

我有一个名为 demo 的 GNU 屏幕,我想向它发送命令。我该怎么做?

screen -S demo -X /home/aa/scripts/outputs.sh

yeilds No screen session found.

并且执行 screen -ls 显示它没有运行。

I have a GNU screen named demo, I want to send commands to it. How do I do this?

screen -S demo -X /home/aa/scripts/outputs.sh

yeilds No screen session found.

and doing screen -ls shows that it isn't running.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

香草可樂 2024-11-15 05:55:40

如果 Screen 会话未运行,您将无法向其发送内容。先开始吧。

建立会话后,您需要区分屏幕命令和键盘输入。 screen -X 需要 Screen 命令。 stuff 命令发送输入,如果您想从 shell 提示符运行该程序,则还必须传递换行符。

screen -S demo -X stuff '/home/aa/scripts/outputs.sh
'

请注意,这可能是错误的方法。您确定要输入该会话中活动的内容吗?要将输入定向到特定窗口,请使用

screen -S demo -p 1 -X stuff '/home/aa/scripts/outputs.sh
'

其中 1 是窗口编号(您可以使用其标题)。

要在该会话中启动新窗口,请改用 screen 命令。 (这是 screen Screen 命令,而不是 screen shell 命令。)

screen -S demo -p 1 -X screen '/home/aa/scripts/outputs.sh'

If the Screen session isn't running, you won't be able to send things to it. Start it first.

Once you've got a session, you need to distinguish between Screen commands and keyboard input. screen -X expects a Screen command. The stuff command sends input, and if you want to run that program from a shell prompt, you'll have to pass a newline as well.

screen -S demo -X stuff '/home/aa/scripts/outputs.sh
'

Note that this may be the wrong approach. Are you sure you want to type into whatever is active in that session? To direct the input at a particular window, use

screen -S demo -p 1 -X stuff '/home/aa/scripts/outputs.sh
'

where 1 is the window number (you can use its title instead).

To start a new window in that session, use the screen command instead. (That's the screen Screen command, not the screen shell command.)

screen -S demo -p 1 -X screen '/home/aa/scripts/outputs.sh'
扮仙女 2024-11-15 05:55:40

我将它们放在一起以捕获命令的输出。如果您想通过管道传输某些输入,它还可以处理标准输入。

function xscreen {
    # Usage: xscreen <screen-name> command...
    local SCREEN_NAME=$1
    shift

    # Create screen if it doesn't exist
    if ! screen -list | grep $SCREEN_NAME >/dev/null ; then
        screen -dmS $SCREEN_NAME
    fi

    # Create I/O pipes
    local DIR=$( mktemp -d )
    local STDIN=$DIR/stdin
    local STDOUT=$DIR/stdout
    local STDERR=$DIR/stderr
    mkfifo $STDIN $STDOUT $STDERR
    trap 'rm -f $STDIN $STDOUT $STDERR; rmdir $DIR' RETURN

    # Print output and kill stdin when both pipes are closed
    { cat $STDERR >&2 & cat $STDOUT & wait ; fuser -s -PIPE -k -w $STDIN ; } &

    # Start the command (Clear line ^A^K, enter command with redirects, run with ^O)
    screen -S $SCREEN_NAME -p0 -X stuff "$(echo -ne '\001\013') { $* ; } <$STDIN 1> >(tee $STDOUT) 2> >(tee $STDERR >&2)$(echo -ne '\015')"

    # Forward stdin
    cat > $STDIN

    # Just in case stdin is closed
    wait
}

更进一步,通过 ssh 调用此函数可能很有用:

ssh user@host -n xscreen somename 'echo hello world'

也许将其与 ssh user@host 之类的东西结合起来"$(typeset -f xscreen); xscreen ..." 因此您不必在远程主机上定义该函数。

bash 脚本中的较长版本,用于处理返回状态和语法错误:

#!/bin/bash

function usage {
    echo "$(basename $0) [[user@]server:[port]] <screen-name> command..." >&2
    exit 1
}

[[ $# -ge 2 ]] || usage

SERVER=
SERVERPORT="-p 22"
SERVERPAT='^(([a-z]+@)?([A-Za-z0-9.]+)):([0-9]+)?

if [[ "$1" =~ $SERVERPAT ]]; then
    SERVER="${BASH_REMATCH[1]}"
    [[ -n "${BASH_REMATCH[4]}" ]] && SERVERPORT="-p ${BASH_REMATCH[4]}"
    shift
fi

function xscreen {
    # Usage: xscreen <screen-name> command...
    local SCREEN_NAME=$1
    shift

    if ! screen -list | grep $SCREEN_NAME >/dev/null ; then
        echo "Screen $SCREEN_NAME not found." >&2
        return 124
        # Create screen if it doesn't exist
        #screen -dmS $SCREEN_NAME
    fi

    # Create I/O pipes
    local DIR=$( mktemp -d )
    mkfifo $DIR/stdin $DIR/stdout $DIR/stderr
    echo 123 > $DIR/status
    trap 'rm -f $DIR/{stdin,stdout,stderr,status}; rmdir $DIR' RETURN

    # Forward ^C to screen
    trap "screen -S $SCREEN_NAME -p0 -X stuff 
\003'" INT

    # Print output and kill stdin when both pipes are closed
    {
        cat $DIR/stderr >&2 &
        cat $DIR/stdout &
        wait
        [[ -e $DIR/stdin ]] && fuser -s -PIPE -k -w $DIR/stdin
    } &
    READER_PID=$!

    # Close all the pipes if the command fails to start (e.g. syntax error)
    {
        # Kill the sleep when this subshell is killed. Ugh.. bash.
        trap 'kill $(jobs -p)' EXIT

        # Try to write nothing to stdin. This will block until something reads.
        echo -n > $DIR/stdin &
        TEST_PID=$!
        sleep 2.0

        # If the write failed and we're not killed, it probably didn't start
        if [[ -e $DIR/stdin ]] && kill $TEST_PID 2>/dev/null; then
            echo 'xscreen timeout' >&2
            wait $TEST_PID 2>/dev/null

            # Send ^C to clear any half-written command (e.g. no closing braces)
            screen -S $SCREEN_NAME -p0 -X stuff 
\003'

            # Write nothing to output, triggers SIGPIPE
            echo -n 1> $DIR/stdout 2> $DIR/stderr

            # Stop stdin by creating a fake reader and sending SIGPIPE
            cat $DIR/stdin >/dev/null &
            fuser -s -PIPE -k -w $DIR/stdin
        fi
    } &
    CHECKER_PID=$!

    # Start the command (Clear line ^A^K, enter command with redirects, run with ^O)
    screen -S $SCREEN_NAME -p0 -X stuff "$(echo -ne '\001\013') { $* ; echo \$? > $DIR/status ; } <$DIR/stdin 1> >(tee $DIR/stdout) 2> >(tee $DIR/stderr >&2)$(echo -ne '\015')"

    # Forward stdin
    cat > $DIR/stdin
    kill $CHECKER_PID 2>/dev/null && wait $CHECKER_PID 2>/dev/null

    # Just in case stdin is closed early, wait for output to finish
    wait $READER_PID 2>/dev/null

    trap - INT

    return $(cat $DIR/status)
}

if [[ -n $SERVER ]]; then
    ssh $SERVER $SERVERPORT "$(typeset -f xscreen); xscreen $@"
    RET=$?
    if [[ $RET == 124 ]]; then
        echo "To start screen: ssh $SERVER $SERVERPORT \"screen -dmS $1\"" >&2
    fi
    exit $RET
else
    xscreen "$1" "${@:2}"
fi

I put this together to capture the output from the commands. It also handles stdin if you want to pipe some input.

function xscreen {
    # Usage: xscreen <screen-name> command...
    local SCREEN_NAME=$1
    shift

    # Create screen if it doesn't exist
    if ! screen -list | grep $SCREEN_NAME >/dev/null ; then
        screen -dmS $SCREEN_NAME
    fi

    # Create I/O pipes
    local DIR=$( mktemp -d )
    local STDIN=$DIR/stdin
    local STDOUT=$DIR/stdout
    local STDERR=$DIR/stderr
    mkfifo $STDIN $STDOUT $STDERR
    trap 'rm -f $STDIN $STDOUT $STDERR; rmdir $DIR' RETURN

    # Print output and kill stdin when both pipes are closed
    { cat $STDERR >&2 & cat $STDOUT & wait ; fuser -s -PIPE -k -w $STDIN ; } &

    # Start the command (Clear line ^A^K, enter command with redirects, run with ^O)
    screen -S $SCREEN_NAME -p0 -X stuff "$(echo -ne '\001\013') { $* ; } <$STDIN 1> >(tee $STDOUT) 2> >(tee $STDERR >&2)$(echo -ne '\015')"

    # Forward stdin
    cat > $STDIN

    # Just in case stdin is closed
    wait
}

Taking it a step further, it can be useful to call this function over ssh:

ssh user@host -n xscreen somename 'echo hello world'

Maybe combine it with something like ssh user@host "$(typeset -f xscreen); xscreen ..." so you don't have to have the function already defined on the remote host.

A longer version in a bash script that handles the return status and syntax errors:

#!/bin/bash

function usage {
    echo "$(basename $0) [[user@]server:[port]] <screen-name> command..." >&2
    exit 1
}

[[ $# -ge 2 ]] || usage

SERVER=
SERVERPORT="-p 22"
SERVERPAT='^(([a-z]+@)?([A-Za-z0-9.]+)):([0-9]+)?

if [[ "$1" =~ $SERVERPAT ]]; then
    SERVER="${BASH_REMATCH[1]}"
    [[ -n "${BASH_REMATCH[4]}" ]] && SERVERPORT="-p ${BASH_REMATCH[4]}"
    shift
fi

function xscreen {
    # Usage: xscreen <screen-name> command...
    local SCREEN_NAME=$1
    shift

    if ! screen -list | grep $SCREEN_NAME >/dev/null ; then
        echo "Screen $SCREEN_NAME not found." >&2
        return 124
        # Create screen if it doesn't exist
        #screen -dmS $SCREEN_NAME
    fi

    # Create I/O pipes
    local DIR=$( mktemp -d )
    mkfifo $DIR/stdin $DIR/stdout $DIR/stderr
    echo 123 > $DIR/status
    trap 'rm -f $DIR/{stdin,stdout,stderr,status}; rmdir $DIR' RETURN

    # Forward ^C to screen
    trap "screen -S $SCREEN_NAME -p0 -X stuff 
\003'" INT

    # Print output and kill stdin when both pipes are closed
    {
        cat $DIR/stderr >&2 &
        cat $DIR/stdout &
        wait
        [[ -e $DIR/stdin ]] && fuser -s -PIPE -k -w $DIR/stdin
    } &
    READER_PID=$!

    # Close all the pipes if the command fails to start (e.g. syntax error)
    {
        # Kill the sleep when this subshell is killed. Ugh.. bash.
        trap 'kill $(jobs -p)' EXIT

        # Try to write nothing to stdin. This will block until something reads.
        echo -n > $DIR/stdin &
        TEST_PID=$!
        sleep 2.0

        # If the write failed and we're not killed, it probably didn't start
        if [[ -e $DIR/stdin ]] && kill $TEST_PID 2>/dev/null; then
            echo 'xscreen timeout' >&2
            wait $TEST_PID 2>/dev/null

            # Send ^C to clear any half-written command (e.g. no closing braces)
            screen -S $SCREEN_NAME -p0 -X stuff 
\003'

            # Write nothing to output, triggers SIGPIPE
            echo -n 1> $DIR/stdout 2> $DIR/stderr

            # Stop stdin by creating a fake reader and sending SIGPIPE
            cat $DIR/stdin >/dev/null &
            fuser -s -PIPE -k -w $DIR/stdin
        fi
    } &
    CHECKER_PID=$!

    # Start the command (Clear line ^A^K, enter command with redirects, run with ^O)
    screen -S $SCREEN_NAME -p0 -X stuff "$(echo -ne '\001\013') { $* ; echo \$? > $DIR/status ; } <$DIR/stdin 1> >(tee $DIR/stdout) 2> >(tee $DIR/stderr >&2)$(echo -ne '\015')"

    # Forward stdin
    cat > $DIR/stdin
    kill $CHECKER_PID 2>/dev/null && wait $CHECKER_PID 2>/dev/null

    # Just in case stdin is closed early, wait for output to finish
    wait $READER_PID 2>/dev/null

    trap - INT

    return $(cat $DIR/status)
}

if [[ -n $SERVER ]]; then
    ssh $SERVER $SERVERPORT "$(typeset -f xscreen); xscreen $@"
    RET=$?
    if [[ $RET == 124 ]]; then
        echo "To start screen: ssh $SERVER $SERVERPORT \"screen -dmS $1\"" >&2
    fi
    exit $RET
else
    xscreen "$1" "${@:2}"
fi
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文