Bash and Expect: Is there a way to ignore or remove ANSI control sequences from Expect buffer? - linux

I'm using Expect to connect to my server over a (virtual) serial port. (HP iLo, to be specific)
When booting from a Linux OS ISO image, you eventually get to the 'boot:' prompt. When my server reaches that prompt, I would like to enter my own custom boot options and press enter. Easy, right?
This is how the boot prompt looks when you're watching my Expect script execute (looks normal):
boot:
However, I have not been able to match 'boot:'. Looking at the Expect Buffer in my logfile, this is what is being captured for that line:
ESC\[25;01HbbESC\[25;01HESC\[25;02HooESC\[25;02HESC\[25;03HooESC\[25;03HESC\[25;04HttESC\[25;04HESC\[25;05H::ESC\[25;05HESC\[25;06H ESC\[25;06HESC\[25;07H"
I think all those control sequences are screwing up my match. If you look closely 'boot:' is actually in there, but it's surrounded by what I believe are ANSI control sequences.
In fact, the logfile is absolutely full of ANSI control characters.
Relevant pieces of the Expect script I've been playing around with:
bash #] expect -d -c '
.....
# SSH to the Virtual Serial Port Management server
spawn ssh user#1.2.3.4
.....
# Access the Virtual Serial Port for the server being booted
send "vsp\r"
.....
# After rebooting the server, when the boot: prompt appears, enter boot options
expect {
"boot:" {send $bootOptions \r\n"}
timeout {send_user "Never found boot prompt\n"; send_user "$expect_out(buffer)"; exit 1}
}
.....
exit'
Any ideas about what the best way to handle those control characters would be? I've tried exporting TERM=dumb and TERM=vt1000 on the machine I'm running the script on. Didn't make much of a difference.

Not sure if this will help, but you could create a wrapper for ssh and exec that instead of ssh and then have
ssh <host> | perl -pe 's/\e([^\[\]]|\[.*?[a-zA-Z]|\].*?\a)//g' | col -b
perhaps take out the col -b which filters newlines if you don't need that.

Related

How to get the output of a telnet command from bash?

I'm trying to get the list of processes running on my Windows machine from Linux, but I don't get any output when I do it in a script. If I use telnet manually and use the command pslist I get the complete list of processes, but not in my script.
Here is the bash script (minus the variables):
( echo open ${host}
sleep 1
echo ${user}
sleep 3
echo ${pass}
sleep 1
echo pslist
sleep 2
) | telnet
and I simply call it with bash pslist.sh and the output is something like that:
telnet> Trying ip_address...
Connected to ip_address.
Escape character is '^]'.
Welcome to Microsoft Telnet Service
login: my_loginmy_passwordpslistConnection closed by foreign host.
What am I doing wrong ?
telnet is notoriously tricky to script. You may be able to succeed more often if you add a longer still sleep between the commands.
A better approach is to switch to a properly scriptable client, viz. netcat (aka nc). Better still would be to install an SSH server on your Windows box (perhaps for security only make it accessible from inside your network) and set it up with passwordless authentication. Then you can simply ssh user#ipaddress pslist
Terminate each echo with \r character, like this: echo -e "${user}\r"

Using gnu screen to access serial port

I am trying to access a device which is attached to a USB-serial port. The settings are 57600 baud, 8 bit, 1 stop bit, no parity. The device outputs a status line every second and accepts typed commands.
I would like to use GNU screen to initiate 2 way communications, so I am using this command:
screen /dev/ttyS2 57600,cs8
However I just get a blank screen, nothing received from the device.
The communication is fine using teraterm, and I can also do this
stty -F /dev/ttyS2 57600 cs8
cat /dev/ttyS2
to see the status output from the device.
I've tried various combinations of ixon, ixoff, crtscts, and clocal but nothing makes any difference.
How can I determine what the correct command should be?
I am using Cygwin on Windows 10.
I faced the same issue with gnu-screen, I started using plink.exe instead from the PuTTY suite. It's not optimal, but it does the job. In my case serial is just for recovery, not for everyday usage.
Start PuTTY, create a profile with your serial connection.
Name and save the connection.
From cygwin, run: '/cygdrive/c/Program\ Files\ (x86)/PuTTY/plink.exe -load SerialProfile'

Replace login prompt with interactive bash script on serial port linux

I am working on a CentOS box.
What I expect: To run my own CLI/setup on startup instead of login prompt on serial console (telnet).
What I did so far:-
I changed call to "agetty" command in serial.conf and serial-ttyUSB0.conf files under /etc/init/, as follows:-
exec /sbin/agetty -n -l <path-to-my-custom-script> ........
My custom.sh script is:-
#!/bin/bash
LOOP_FLAG=0
while [ $LOOP_FLAG -eq 0 ]; do
for TTY in /dev/ttyS0 /dev/tty0; do
echo "Please choose to enter in 'setup' or 'cli'. (s/c)? " > $TTY
done
read sc
case $sc in
[Ss]* ) LOOP_FLAG=1; <some-executable-cli-file-path>; break;;
[Cc]* ) LOOP_FLAG=1; <some-executable-setup-file-path>; break;;
* ) for TTY in /dev/ttyS0 /dev/tty0; do
echo "Please press 's' or 'c'." >$TTY
done;;
esac
done
But when system boots, on a telnet session, I could only see the "Please choose to enter.." question on screen and after that I couldn't able to type anything on console.
One more update:
If I run the above agetty command on shell prompt as it is (say from ssh session), then it works fine on serial console (telnet). But, from the above startup scripts, it doesn't work.
Can anybody help me out with this?
Thanks in advance.
-Neo
Sorry I'm a few years late. Hopefully this will be of help for people searching for solution to this problem in the future.
The issue lies here:
-n, --skip-login Do not prompt the user for a login name. This can be used in connection with -l option to invoke a non-standard login
process such as a BBS system. Note that with the -n option, agetty
gets no input from user who logs in and therefore won't be able to
figure out parity, character size, and newline processing of the
connection. It defaults to space parity, 7 bit characters, and ASCII
CR (13) end-of-line character. Beware that the program that agetty
starts (usually /bin/login) is run as root.
So you need to initialize the terminal yourself in the script you are replacing the login prompt with. I found the settings below work well:
/bin/stty -F /dev/ttyO0 115200 cs8 sane
Remember to replace the baud rate and terminal name to your own.

linux execute command remotely

how do I execute command/script on a remote linux box?
say I want to do service tomcat start on box b from box a.
I guess ssh is the best secured way for this, for example :
ssh -OPTIONS -p SSH_PORT user#remote_server "remote_command1; remote_command2; remote_script.sh"
where the OPTIONS have to be deployed according to your specific needs (for example, binding to ipv4 only) and your remote command could be starting your tomcat daemon.
Note:
If you do not want to be prompt at every ssh run, please also have a look to ssh-agent, and optionally to keychain if your system allows it. Key is... to understand the ssh keys exchange process. Please take a careful look to ssh_config (i.e. the ssh client config file) and sshd_config (i.e. the ssh server config file). Configuration filenames depend on your system, anyway you'll find them somewhere like /etc/sshd_config. Ideally, pls do not run ssh as root obviously but as a specific user on both sides, servers and client.
Some extra docs over the source project main pages :
ssh and ssh-agent
man ssh
http://www.snailbook.com/index.html
https://help.ubuntu.com/community/SSH/OpenSSH/Configuring
keychain
http://www.gentoo.org/doc/en/keychain-guide.xml
an older tuto in French (by myself :-) but might be useful too :
http://hornetbzz.developpez.com/tutoriels/debian/ssh/keychain/
ssh user#machine 'bash -s' < local_script.sh
or you can just
ssh user#machine "remote command to run"
If you don't want to deal with security and want to make it as exposed (aka "convenient") as possible for short term, and|or don't have ssh/telnet or key generation on all your hosts, you can can hack a one-liner together with netcat. Write a command to your target computer's port over the network and it will run it. Then you can block access to that port to a few "trusted" users or wrap it in a script that only allows certain commands to run. And use a low privilege user.
on the server
mkfifo /tmp/netfifo; nc -lk 4201 0</tmp/netfifo | bash -e &>/tmp/netfifo
This one liner reads whatever string you send into that port and pipes it into bash to be executed. stderr & stdout are dumped back into netfifo and sent back to the connecting host via nc.
on the client
To run a command remotely:
echo "ls" | nc HOST 4201

How to send data to local clipboard from a remote SSH session

Borderline ServerFault question, but I'm programming some shell scripts, so I'm trying here first :)
Most *nixes have a command that will let you pipe/redirect output to the local clipboard/pasteboard, and retrieve from same. On OS X these commands are
pbcopy, pbpaste
Is there anyway to replicate this functionality while SSHed into another server? That is,
I'm using Computer A.
I open a terminal window
I SSH to Computer B
I run a command on Computer B
The output of Computer B is redirected or automatically copied to Computer A's clipboard.
And yes, I know I could just (shudder) use my mouse to select the text from the command, but I've gotten so used to the workflow of pipping output directly to the clipboard that I want the same for my remote sessions.
Code is useful, but general approaches are appreciated as well.
My favorite way is ssh [remote-machine] "cat log.txt" | xclip -selection c. This is most useful when you don't want to (or can't) ssh from remote to local.
Edit: on Cygwin ssh [remote-machine] "cat log.txt" > /dev/clipboard.
Edit: A helpful comment from nbren12:
It is almost always possible to setup a reverse ssh connection using SSH port forwarding. Just add RemoteForward 127.0.0.1:2222 127.0.0.1:22 to the server's entry in your local .ssh/config, and then execute ssh -p 2222 127.0.0.1 on the remote machine, which will then redirect the connection to the local machine. – nbren12
I'm resurrecting this thread because I've been looking for the same kind of solution, and I've found one that works for me. It's a minor modification to a suggestion from OSX Daily.
In my case, I use Terminal on my local OSX machine to connect to a linux server via SSH. Like the OP, I wanted to be able to transfer small bits of text from terminal to my local clipboard, using only the keyboard.
The essence of the solution:
commandThatMakesOutput | ssh desktop pbcopy
When run in an ssh session to a remote computer, this command takes the output of commandThatMakesOutput (e.g. ls, pwd) and pipes the output to the clipboard of the local computer (the name or IP of "desktop"). In other words, it uses nested ssh: you're connected to the remote computer via one ssh session, you execute the command there, and the remote computer connects to your desktop via a different ssh session and puts the text to your clipboard.
It requires your desktop to be configured as an ssh server (which I leave to you and google). It's much easier if you've set up ssh keys to facilitate fast ssh usage, preferably using a per-session passphrase, or whatever your security needs require.
Other examples:
ls | ssh desktopIpAddress pbcopy
pwd | ssh desktopIpAddress pbcopy
For convenience, I've created a bash file to shorten the text required after the pipe:
#!/bin/bash
ssh desktop pbcopy
In my case, i'm using a specially named key
I saved it with the file name cb (my mnemonic (ClipBoard). Put the script somewhere in your path, make it executable and voila:
ls | cb
Found a great solution that doesn't require a reverse ssh connection!
You can use xclip on the remote host, along with ssh X11 forwarding & XQuartz on the OSX system.
To set this up:
Install XQuartz (I did this with soloist + pivotal_workstation::xquartz recipe, but you don't have to)
Run XQuartz.app
Open XQuartz Preferences (+,)
Make sure "Enable Syncing" and "Update Pasteboard when CLIPBOARD changes" are checked
ssh -X remote-host "echo 'hello from remote-host' | xclip -selection clipboard"
Reverse tunnel port on ssh server
All the existing solutions either need:
X11 on the client (if you have it, xclip on the server works great) or
the client and server to be in the same network (which is not the case if you're at work trying to access your home computer).
Here's another way to do it, though you'll need to modify how you ssh into your computer.
I've started using this and it's nowhere near as intimidating as it looks so give it a try.
Client (ssh session startup)
ssh username#server.com -R 2000:localhost:2000
(hint: make this a keybinding so you don't have to type it)
Client (another tab)
nc -l 2000 | pbcopy
Note: if you don't have pbcopy then just tee it to a file.
Server (inside SSH session)
cat some_useful_content.txt | nc localhost 2000
Other notes
Actually even if you're in the middle of an ssh session there's a way to start a tunnel but i don’t want to scare people away from what really isn’t as bad as it looks. But I'll add the details later if I see any interest
There are various tools to access X11 selections, including xclip and XSel. Note that X11 traditionally has multiple selections, and most programs have some understanding of both the clipboard and primary selection (which are not the same). Emacs can work with the secondary selection too, but that's rare, and nobody really knows what to do with cut buffers...
$ xclip -help
Usage: xclip [OPTION] [FILE]...
Access an X server selection for reading or writing.
-i, -in read text into X selection from standard input or files
(default)
-o, -out prints the selection to standard out (generally for
piping to a file or program)
-l, -loops number of selection requests to wait for before exiting
-d, -display X display to connect to (eg localhost:0")
-h, -help usage information
-selection selection to access ("primary", "secondary", "clipboard" or "buffer-cut")
-noutf8 don't treat text as utf-8, use old unicode
-version version information
-silent errors only, run in background (default)
-quiet run in foreground, show what's happening
-verbose running commentary
Report bugs to <astrand#lysator.liu.se>
$ xsel -help
Usage: xsel [options]
Manipulate the X selection.
By default the current selection is output and not modified if both
standard input and standard output are terminals (ttys). Otherwise,
the current selection is output if standard output is not a terminal
(tty), and the selection is set from standard input if standard input
is not a terminal (tty). If any input or output options are given then
the program behaves only in the requested mode.
If both input and output is required then the previous selection is
output before being replaced by the contents of standard input.
Input options
-a, --append Append standard input to the selection
-f, --follow Append to selection as standard input grows
-i, --input Read standard input into the selection
Output options
-o, --output Write the selection to standard output
Action options
-c, --clear Clear the selection
-d, --delete Request that the selection be cleared and that
the application owning it delete its contents
Selection options
-p, --primary Operate on the PRIMARY selection (default)
-s, --secondary Operate on the SECONDARY selection
-b, --clipboard Operate on the CLIPBOARD selection
-k, --keep Do not modify the selections, but make the PRIMARY
and SECONDARY selections persist even after the
programs they were selected in exit.
-x, --exchange Exchange the PRIMARY and SECONDARY selections
X options
--display displayname
Specify the connection to the X server
-t ms, --selectionTimeout ms
Specify the timeout in milliseconds within which the
selection must be retrieved. A value of 0 (zero)
specifies no timeout (default)
Miscellaneous options
-l, --logfile Specify file to log errors to when detached.
-n, --nodetach Do not detach from the controlling terminal. Without
this option, xsel will fork to become a background
process in input, exchange and keep modes.
-h, --help Display this help and exit
-v, --verbose Print informative messages
--version Output version information and exit
Please report bugs to <conrad#vergenet.net>.
In short, you should try xclip -i/xclip -o or xclip -i -sel clip/xclip -o -sel clip or xsel -i/xsel -o or xsel -i -b/xsel -o -b, depending on what you want.
If you use iTerm2 on the Mac, there is an easier way. This functionality is built into iTerm2's Shell Integration capabilities via the it2copy command:
Usage: it2copy
Copies to clipboard from standard input
it2copy filename
Copies to clipboard from file
To make it work, choose iTerm2-->Install Shell Integration menu item while logged into the remote host, to install it to your own account. Once that is done, you'll have access to it2copy, as well as a bunch of other aliased commands that provide cool functionality.
The other solutions here are good workarounds but this one is so painless in comparison.
This is my solution based on SSH reverse tunnel, netcat and xclip.
First create script (eg. clipboard-daemon.sh) on your workstation:
#!/bin/bash
HOST=127.0.0.1
PORT=3333
NUM=`netstat -tlpn 2>/dev/null | grep -c " ${HOST}:${PORT} "`
if [ $NUM -gt 0 ]; then
exit
fi
while [ true ]; do
nc -l ${HOST} ${PORT} | xclip -selection clipboard
done
and start it in background.
./clipboard-daemon.sh&
It will start nc piping output to xclip and respawning process after receiving portion of data
Then start ssh connection to remote host:
ssh user#host -R127.0.0.1:3333:127.0.0.1:3333
While logged in on remote box, try this:
echo "this is test" >/dev/tcp/127.0.0.1/3333
then try paste on your workstation
You can of course write wrapper script that starts clipboard-daemon.sh first and then ssh session. This is how it works for me. Enjoy.
Allow me to add a solution that if I'm not mistaken was not suggested before.
It does not require the client to be exposed to the internet (no reverse connections), nor does it use any xlibs on the server and is implemented completely using ssh's own capabilities (no 3rd party bins)
It involves:
Opening a connection to the remote host, then creating a fifo file on it and waiting on that fifo in parallel (same actual TCP connection for everything).
Anything you echo to that fifo file ends up in your local clipboard.
When the session is done, remove the fifo file on the server and cleanly terminate the connections together.
The solution utilizes ssh's ControlMaster functionality to use just one TCP connection for everything so it will even support hosts that require a password to login and prompt you for it just once.
Edit: as requested, the code itself:
Paste the following into your bashrc and use sshx host to connect.
On the remote machine echo SOMETHING > ~/clip and hopefully, SOMETHING will end up in the local host's clipboard.
You will need the xclip utility on your local host.
_dt_term_socket_ssh() {
ssh -oControlPath=$1 -O exit DUMMY_HOST
}
function sshx {
local t=$(mktemp -u --tmpdir ssh.sock.XXXXXXXXXX)
local f="~/clip"
ssh -f -oControlMaster=yes -oControlPath=$t $# tail\ -f\ /dev/null || return 1
ssh -S$t DUMMY_HOST "bash -c 'if ! [ -p $f ]; then mkfifo $f; fi'" \
|| { _dt_term_socket_ssh $t; return 1; }
(
set -e
set -o pipefail
while [ 1 ]; do
ssh -S$t -tt DUMMY_HOST "cat $f" 2>/dev/null | xclip -selection clipboard
done &
)
ssh -S$t DUMMY_HOST \
|| { _dt_term_socket_ssh $t; return 1; }
ssh -S$t DUMMY_HOST "rm $f"
_dt_term_socket_ssh $t
}
More detailed explanation is on my website:
https://xicod.com/2021/02/09/clipboard-over-ssh.html
The simplest solution of all, if you're on OS X using Terminal and you've been ssh'ing around in a remote server and wish to grab the results of a text file or a log or a csv, simply:
1) Cmd-K to clear the output of the terminal
2) cat <filename> to display the contents of the file
3) Cmd-S to save the Terminal Output
You'll have the manually remove the first line and last line of the file, but this method is a bit simpler than relying on other packages to be installed, "reverse tunnels" and trying to have a static IP, etc.
This answer develops both upon the chosen answer by adding more security.
That answer discussed the general form
<command that makes output> | \
ssh <user A>#<host A> <command that maps stdin to clipboard>
Where security may be lacking is in the ssh permissions allowing <user B> on host B> to ssh into host A and execute any command.
Of course B to A access may already be gated by an ssh key, and it may even have a password. But another layer of security can restrict the scope of allowable commands that B can execute on A, e.g. so that rm -rf / cannot be called. (This is especially important when the ssh key doesn't have a password.)
Fortunately, ssh has a built-in feature called command restriction or forced command. See ssh.com, or
this serverfault.com question.
The solution below shows the general form solution along with ssh command restriction enforced.
Example Solution with command restriction added
This security enhanced solution follows the general form - the call from the ssh session on host-B is simply:
cat <file> | ssh <user-A>#<host A> to_clipboard
The rest of this shows the setup to get that to work.
Setup of ssh command restriction
Suppose the user account on B is user-B, and B has an ssh key id-clip, that has been created in the usual way (ssh-keygen).
Then in user-A's ssh directory there is a file
/home/user-A/.ssh/authorized_keys
that recognizes the key id-clip and allows ssh connection.
Usually the contents of each line authorized_keys is exactly the public key being authorized, e.g., the contents of id-clip.pub.
However, to enforce command restriction that public key content is prepended (on the same line) by the command to be executed.
In our case:
command="/home/user-A/.ssh/allowed-commands.sh id-clip",no-agent-forwarding,no-port-forwarding,no-user-rc,no-x11-forwarding,no-pty <content of file id-clip.pub>
The designated command "/home/user-A/.ssh/allowed-commands.sh id-clip", and only that designated command, is executed whenever key id-clip is used initiate an ssh connection to host-A - no matter what command is written the ssh command line.
The command indicates a script file allowed-commands.sh, and the contents of that that script file is
#/bin/bash
#
# You can have only one forced command in ~/.ssh/authorized_keys. Use this
# wrapper to allow several commands.
Id=${1}
case "$SSH_ORIGINAL_COMMAND" in
"to-clipboard")
notify-send "ssh to-clipboard, from ${Id}"
cat | xsel --display :0 -i -b
;;
*)
echo "Access denied"
exit 1
;;
esac
The original call to ssh on machine B was
... | ssh <user-A>#<host A> to_clipboard
The string to-clipboard is passed to allowed-commands.sh by the environment variable SSH_ORIGINAL_COMMAND.
Addition, we have passed the name of the key, id-clip, from the line in authorized_keyswhich is only accessed by id-clip.
The line
notify-send "ssh to-clipboard, from ${Id}"
is just a popup messagebox to let you know the clipboard is being written - that's probably a good security feature too. (notify-send works on Ubuntu 18.04, maybe not others).
In the line
cat | xsel --display :0 -i -b
the parameter --display :0 is necessary because the process doesn't have it's own X display with a clipboard,
so it must be specificied explicitly. This value :0 happens to work on Ubuntu 18.04 with Wayland window server. On other setups it might not work. For a standard X server this answer might help.
host-A /etc/ssh/sshd_config parameters
Finally a few parameters in /etc/ssh/sshd_config on host A that should be set to ensure permission to connect, and permission to use ssh-key only without password:
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
AllowUsers user-A
To make the sshd server re-read the config
sudo systemctl restart sshd.service
or
sudo service sshd.service restart
conclusion
It's some effort to set it up, but other functions besides to-clipboard can be constructed in parallel the same framework.
Not a one-liner, but requires no extra ssh.
install netcat if necessary
use termbin: cat ~/some_file.txt | nc termbin.com 9999. This will copy the output to the termbin website and prints the URL to your output.
visit that url from your computer, you get your output
Of course, do not use it for sensitive content.
#rhileighalmgren solution is good, but pbcopy will annoyingly copy last "\n" character, I use "head" to strip out last character to prevent this:
#!/bin/bash
head -c -1 | ssh desktop pbcopy
My full solution is here : http://taylor.woodstitch.com/linux/copy-local-clipboard-remote-ssh-server/
Far Manager Linux port supports synchronizing clipboard between local and remote host. You just open local far2l, do "ssh somehost" inside, run remote far2l in that ssh session and get remote far2l working with your local clipboard.
It supports Linux, *BSD and OS X; I made a special putty build to utilize this functionality from windows also.
For anyone googling their way to this:
The best solution in this day and age seem to be lemonade
Various solutions is also mentioned in the neovim help text for clipboard-tool
If you're working over e.g. a pod in a Kubernetes cluster and not direct SSH, so that there is no way for your to do a file transfer, you could use cat and then save the terminal output as text. For example in macOS you can do Shell -> Export as text.

Resources