简体   繁体   English

如何在Bash脚本中使用Expect生成预填充的终端会话

[英]How to use Expect within a Bash script to generate pre populated terminal sessions

I asked a slightly different version of this a few months back and never got it to work properly, this question has moved on a bit and has new code blocks. 几个月前,我询问了与此版本稍有不同的版本,但从未使其正常运行,这个问题已经发展了一些,并且有新的代码块。

When I log onto my assorted PCs I usually have a number of things I want to happen automatically, but not always straight away. 当我登录各式各样的PC时,通常会遇到很多我想自动发生的事情,但并不总是立刻发生。

These include starting terminal sessions in specific locations on specific workspaces (because you get used to using the same layout) and those terminal sessions performing specific acts such as ssh commands (I DO NOT want to embed passwords into the script in any way or piped, just want to populate the command into terminal session so that when I eventually get to that specific terminal session I just need to hit enter). 其中包括在特定工作区的特定位置启动终端会话(因为您习惯使用相同的布局),以及执行特定行为(例如ssh命令)的终端会话(我不希望以任何方式或通过管道将密码嵌入脚本中,只是想将命令填充到终端会话中,这样当我最终到达那个特定的终端会话时,我只需要按Enter键即可。

However sometimes when you logon after a reboot you may not want to execute those commands immediately as a higher priority action may need your attention first. 但是,有时在重新引导后登录时,您可能不想立即执行这些命令,因为优先级较高的操作可能需要首先引起您的注意。

So....what I want is my login script to open terminal sessions and have session commands for that specific terminal session pre populated on the command line, but not yet executed. 所以....我想要的是我的登录脚本来打开终端会话,并在命令行上预填充该特定终端会话的会话命令,但尚未执行。

I use Mate and Compiz as my DE as I like its flexibility. 我喜欢Mate和Compiz作为我的DE,因为我喜欢它的灵活性。

At the moment my bash script looks life this. 目前,我的bash脚本看起来很生动。

#!/bin/bash

# This script is to open a number of windows at specific locations and execute startup commands in those windows.
# It's designed to save time on a new boot up environment and keep the environment consistent.


# Define function to see which ViewPort we are currently on



CurrentViewportQuery () {

TOTALAREA=`wmctrl -d | awk '{print $4}' | awk -F'x' '{print $1}'`

VPAREA=`wmctrl -d | awk '{print $9}' | awk -F'x' '{print $1}'`

CURRENTVPORTREF=`wmctrl -d | awk '{print $6}' | awk -F',' '{print $1}'`

TOTALVPORTS=`echo "$TOTALAREA/$VPAREA" | bc`

CURRENTVPORT=`echo "($CURRENTVPORTREF/$VPAREA)+1" | bc`

 }

# TerminalSessionTargets () {



CurrentViewportQuery

#  echo "totalarea $TOTALAREA vparea $VPAREA currentvportref $CURRENTVPORTREF totalvports $TOTALVPORTS currentvport $CURRENTVPORT"

#  exit 99 # Debug Exit Point

# The following sleep is to allow compiz to fire up fully before we open the terminal sessions or else compositing isn't enabled when the terminal sessions open leading to time based inconsistencies.

sleep 3

#  The following defines the number of terminal session I want for this version of the script, the location onscreen and the target IP address for the ssh session
# In this instance 9 terminal sessions spread over 3 workspaces starting at workspace 3 (this version of the script runs on a machine with a 4k screen)

TERM[0]="24"
TERMLOC[0]="180+400"
TERM[1]="25"
TERMLOC[1]="1305+400"
TERM[2]="xxx"
TERMLOC[2]="2430+400"
TERM[3]="112"
TERMLOC[3]="180+400"
TERM[4]="117"
TERMLOC[4]="1305+400"
TERM[5]="xxx"
TERMLOC[5]="2430+400"
TERM[6]="191"
TERMLOC[6]="180+400"
TERM[7]="193"
TERMLOC[7]="1305+400"
TERM[8]="xxx"
TERMLOC[8]="2430+400"


STARTTERM="0"

FIRSTTARGETVPORT="3"
# FIRSTTARGETVPORT="5"  #  Temp line for code testing  
LASTTARGETVPORT=$((TOTALVPORTS))
NUMBEROFTARGETVPORTS=$((TOTALVPORTS-(FIRSTTARGETVPORT-1)))
NUMBERTERMSPERVPORT=$((${#TERM[*]}/NUMBEROFTARGETVPORTS))

echo "last targetvport $LASTTARGETVPORT numbertargetvports $NUMBEROFTARGETVPORTS termspervport $NUMBERTERMSPERVPORT"  #  Debug output so I can confirm location of spawned terminal session


# Turn off touch sensitive screen

SCREENVALUE=`xinput | grep 'Touchscreen' | cut -f 2 | sed 's/id=//'`

xinput --set-prop $SCREENVALUE 'Device Enabled' 0

# exit

# First lets calculate how many workspaces we have on this machine

CurrentViewportQuery

# Now the dimensions of each viewport

for ((i=1;$i<=$(($TOTALAREA / $VPAREA));i++)); do
VPORT[$i]=$(($VPAREA * ($i-1))) #sets the array entry at index $i to the next viewsize. Remember that $i increases by one every loop

done

#  Now lets open the sshdesktops desktops in viewport 3

FIRSTVPORTTERM="$STARTTERM"

let LASTVPORTTERM="$STARTTERM+($NUMBERTERMSPERVPORT-1)"  # The -1 is to make sure the first term which is number 0 is included

for NEXTTARGETVPORT in `eval echo {$FIRSTTARGETVPORT..$LASTTARGETVPORT}`; do

echo "targetvport ${NEXTTARGETVPORT}"

wmctrl -o ${VPORT[NEXTTARGETVPORT]},0

until [ $CURRENTVPORT -eq $NEXTTARGETVPORT ]; do

CurrentViewportQuery

done

for THISVPORTSTERMS in `eval echo {$FIRSTVPORTTERM..$LASTVPORTTERM}`; do


expect -c " spawn -noecho mate-terminal --window-with-profile=default --geometry=85x24+${TERMLOC[THISVPORTSTERMS]} --title='SSH${TERM[THISVPORTSTERMS]}';
expect \">:\";
send \"ssh root@192.168.12.${TERM[THISVPORTSTERMS]}\";
interact;
expect eof;"

done

Now the script runs fine in terms of identifying the workspaces correctly, switching to the correct workspace and the expect -c command near the bottom of the code block is spawning the mate-terminal session at the correct location on each workspace, however it's not populating the terminal session with the required ssh command (basically the send \\"ssh@192.168......" bit isn't working). 现在,该脚本在正确识别工作区,切换到正确的工作区方面运行良好,并且代码块底部附近的期望-c命令在每个工作区的正确位置生成了mate-terminal会话,但是并未填充带有必需的ssh命令的终端会话(基本上,发送\\“ ssh@192.168 ......”位不起作用)。

I've tried various syntax versions and revisited this now a few times when I've had a few minutes on my hands....but so far no joy so am back here asking again. 我已经尝试了各种语法版本,并且在我花了几分钟的时间后重新讨论了一下。...但是到目前为止,还没有喜悦,所以我再次回到这里询问。

It would help if you reduced your examples to the minimum necessary. 如果将示例减少到最低限度,这将有所帮助。 In your case the problem is that when you spawn mate-terminal , expect creates a pseudo-tty pty between it and the command, but then mate-terminal creates another pty and runs the shell in it. 在您的情况下,问题是当您生成mate-terminalexpect在它和命令之间创建了一个伪tty pty,但是随后mate-terminal创建了另一个pty并在其中运行外壳程序。 So your send command is sent to something that is going to ignore it. 因此,您的send命令被发送到将忽略它的东西。

What you need to do is, for example, run the expect command inside the mate-terminal as in: 您需要做的是,例如,在mate-terminal内部运行expect命令,如下所示:

mate-terminal -x expect -c 'spawn bash -i; send "echo hello";interact'

This is still a little inefficient as we still have two pty's. 这仍然有些效率低下,因为我们还有两个问题。 So an alternative is to use the ioctl TIOCSTI which can push characters onto the input of a pty. 因此,另一种方法是使用ioctl TIOCSTI ,它可以将字符推送到pty的输入上。 Write a simple perl script, pushtype with 编写一个简单的perl脚本, pushtype

#!/usr/bin/perl
# push characters onto tty input queue as if typed
# see man tty_ioctl. https://stackoverflow.com/a/45130404/5008284
use strict;
require 'sys/ioctl.ph';
foreach my $ch (split('',join(" ",@ARGV))){
  ioctl(STDOUT, &TIOCSTI, $ch) or die $!;
}

and then you can do use 然后你可以使用

mate-terminal -x bash -c 'pushtype "echo hello"; exec bash -i'

and you will have the echo hello ready in the input of your shell, with no need for another pty. 这样,您就可以在shell的输入中准备好echo hello了,而无需另外输入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM