\ r \ n来自哪里?

时间:2014-12-17 17:12:05

标签: string bash perl expect carriage-return

我正在尝试解决我需要登录众多的情况 服务器无法使用ssh密钥。结果我 制定一个"这是一个不好的做法" -expect script:

#!/usr/bin/expect
set arg1 [lindex $argv 0]
spawn ssh $arg1 -l user "hostname; env x='() { :;}; echo vulnerable' bash -c \"echo this is a test\"; echo"
expect " password:"
send "my_supersecret_password\n"
interact

运行它可以正常工作:

$ ./ssh.expect server
spawn ssh server -l user hostname; env x='() { :;}; echo vulnerable' bash -c "echo this is a test"; echo
user@server's password:
server
this is a test

$

但是在多个系统上运行时我需要一个更好的格式化列表,所以我尝试让perl重新格式化数据:

$ ./ssh.expect server | perl -e '$dump = <>; $dump = <>; chomp($line1 = <>); chomp($line2 = <>); $dump = <>; print "$line1:$line2\n";'
:this is a test

打印服务器名称,就像它以\ r结尾一样。我不认为应该这样做。你同意吗?如何在打印服务器名称后让系统不返回到第0列?

我可以通过在我的print上添加换行来验证这两个变量是否包含数据:

$ ./ssh.expect server | perl -e '$dump = <>; $dump = <>; chomp($line1 = <>); chomp($line2 = <>); $dump = <>; print "$line1\n:$line2\n";'
server
:this is a test

编辑:

如评论所述,以下工作。

./ssh.expect server | tr -d '\r' | perl -e '$dump = <>; $dump = <>; chomp($line1 = <>); chomp($line2 = <>); $dump = <>; print "$line1:$line2\n";'
server:this is a test

不应该让tr冗余吗?

2 个答案:

答案 0 :(得分:2)

Expect使用伪TTY与它产生的命令进行通信,在这种情况下是ssh进程。默认情况下,TTY和PTY将在输出文本中将\ n转换为\ r \ n(LF到CRLF)。因此,除非您努力删除CR,否则您的expect脚本的输出将包含CRLF序列。您可以通过以交互方式运行expect来查看此内容:

$ expect -c 'spawn echo foo; interact' | od -a
0000000    s   p   a   w   n  sp   e   c   h   o  sp   f   o   o  cr  nl
0000020    f   o   o  cr  nl                                            
0000025               ^^--^^--note

TTY LF-&gt; CRLF转换由TTY&#34; onlcr&#34;旗。我在期待剧本中打开了那个标志但是没有成功。

Perl的chomp命令删除perl输入记录分隔符($/变量)的序列,这些序列在Unix系统上只是\ n。换句话说,默认情况下,\ r对unix上的chomp并不特殊。如果您愿意,可以在perl脚本中更改$/以使chomp删除回车符。或者您可以通过tr管理期望脚本的输出,如上所述。

答案 1 :(得分:0)

终端使用

\r;键盘上的Enter键实际发送\r,Linux内核将其转换为\n; \r\n是输出到终端的行,Linux内核在输出时将\n转换为它。可以禁用这些翻译,将终端置于“原始模式”,程序可以直接与终端通话(参见http://www.linusakesson.net/programming/tty/)。这是全屏程序所必需的,例如vinethack

我的猜测是ssh将终端置于客户端(您的终端)的原始模式,因此服务器端的内核可以执行\n - &gt;关于输出的\r\n翻译。这使您可以在vi下运行ssh,但这意味着当您在程序下运行ssh时需要假装成终端,这意味着发送\r作为EOL输出并在输入时读取\r\n作为EOL。