我写了一个简单的包装脚本,用于在失败时重复命令retry.py.但是,由于我想看到子命令的输出,我不得不拉一些pty技巧.这适用于像rsync这样的程序,但是像scp这样的其他程序会应用额外的测试来显示像进度表这样的东西.
scp代码有一个广泛的测试:
getpgrp() == tcgetpgrp(STDOUT_FILENO);
Run Code Online (Sandbox Code Playgroud)
当我运行包装器脚本时,这会失败.正如您在我的简单tty_test.c测试用例中看到的:
./tty_tests
isatty reports 1
pgrps are 13619 and 13619
Run Code Online (Sandbox Code Playgroud)
和:
./retry.py -v -- ./tty_tests
command is ['./tty_tests']
isatty reports 1
pgrps are 13614 and -1
child finished: rc = 0
Ran command 1 times
Run Code Online (Sandbox Code Playgroud)
我已经尝试使用tcsetpgrp(),最终作为pty fd的IOCTL,但这导致了ptys的-EINVAL.如果可能的话,我宁愿继续使用Python子进程机器,还是需要手动fork/execve'ing?
slave fd被另一个应用程序(比如"A")用作串行端口设备.
A将设置其波特率/停止位等.我的应用程序需要此信息.
顺便说一下,有没有办法让只有主fd打开的进程被通知所有ioctl()发给奴隶fd的电话?
我想从Python调用一个程序,并让它相信stdout即使Python的进程stdout附加到管道上它也是一个tty.所以我使用该pty.spawn函数来实现这一点,可以从以下方面进行验证:
$ python -c "import sys; from subprocess import call; call(sys.argv[1:])" python -c "import sys; print sys.stdout.isatty()" | cat
False
$ python -c "import sys; import pty; pty.spawn(sys.argv[1:])" python -c "import sys; print sys.stdout.isatty()" | cat
True
Run Code Online (Sandbox Code Playgroud)
(我们看到在第二个命令中我们已经实现了我们的目标,即生成的进程被欺骗认为它的标准输出是tty.)
但问题是如果我们使用pty.spawn那么它的输入不会被回显,而是被重定向到主的标准输出.这可以通过以下命令看到:
$ python -c "import sys; import pty; pty.spawn(sys.argv[1:])" cat > out.txt
$ # Typed "hello" in input, but that is not echoed (use ^D to exit). It is redirected to output.txt
$ cat out.txt
hello …Run Code Online (Sandbox Code Playgroud) 我正在尝试开发一个简单的“telnet/server”守护进程,它必须在新的套接字连接上运行一个程序。这部分工作正常。
但是我必须将我的新进程与 pty 相关联,因为该进程具有一些终端功能(如 readline)。
我开发的代码是(其中 socketfd 是新输入连接的新套接字文件描述符):
int masterfd, pid;
const char *prgName = "...";
char *arguments[10] = ....;
if ((pid = forkpty(&masterfd, NULL, NULL, NULL)) < 0)
perror("FORK");
else if (pid)
return pid;
else
{
close(STDOUT_FILENO);
dup2(socketfd, STDOUT_FILENO);
close(STDIN_FILENO);
dup2(socketfd, STDIN_FILENO);
close(STDERR_FILENO);
dup2(socketfd, STDERR_FILENO);
if (execvp(prgName, arguments) < 0)
{
perror("execvp");
exit(2);
}
}
Run Code Online (Sandbox Code Playgroud)
使用该代码,我的“prgName”的 stdin / stdout / stderr 文件描述符与套接字相关联(使用 ls -la /proc/PID/fd 查看时),因此,此进程的终端功能不起作用.
通过远程设备上的 ssh/sshd 连接进行测试,并执行“localy”(在 ssh 连接下)prgName,表明此进程“prgName”的 stdin/stdout/stderr fd 与 pty(等等)相关联此过程的终端功能运行良好)。
我做错了什么?如何将我的 socketfd 与 pty(由 …
我正在尝试将如下所示的 Python 代码移植到 Ruby:
import pty
pid, fd = pty.fork
if pid == 0:
# figure out what to launch
cmd = get_command_based_on_user_input()
# now replace the forked process with the command
os.exec(cmd)
else:
# read and write to fd like a terminal
Run Code Online (Sandbox Code Playgroud)
由于我需要像终端一样读取和写入子进程,我明白我应该使用 Ruby 的 PTY 模块来代替 Kernel.fork。但它似乎没有等效的 fork 方法;我必须将命令作为字符串传递。这是我能得到的最接近 Python 功能的方法:
require 'pty'
# The Ruby executable, ready to execute some codes
RUBY = %Q|/proc/#{Process.id}/exe -e "%s"|
# A small Ruby program which will eventually replace itself with …Run Code Online (Sandbox Code Playgroud) 我在 Windows 上安装了 Ruby 1.9.3。当我尝试要求 gem 时,控制台输出找不到 gem:
require 'pty'
Run Code Online (Sandbox Code Playgroud)
哪个输出:
'require': cannot load such file -- pty <LoadError>
Run Code Online (Sandbox Code Playgroud)
我也尝试过:
gem install pty
Run Code Online (Sandbox Code Playgroud)
并得到这个输出:
Could not find a valid gem 'pty' in any repository
Run Code Online (Sandbox Code Playgroud)
我该如何解决?
我正在编写一个终端日志程序- 想想这个script命令,但功能更强大。区别之一是,虽然script将 stdout、stdin 和 stderr 捕获为一个大字符流,但我希望将它们分开并按原样记录。
为了做到这一点,我使用了运行连接到 pty 的子 shell 的标准方法,但我使用了两个 pty——stdin 和 stderr 连接到了两个 pty,而不是使用一个带有 stdin、stdout 和 stderr 的单个 pty。一个 pty,另一个是标准输出。这样,主进程就可以分辨出什么来自 stdout,什么来自 stderr。
到目前为止,这运行良好。但是,我开始遇到一些问题。例如,当尝试设置列数时,我得到以下信息:
$stty cols 169
stty:stdout 出现重定向,但 stdin 是控制描述符
这似乎是这段代码的结果,它似乎检查 stdout 和 stderr 是否都是 ttys,但如果它们不一样就会抱怨。
因此,我的问题是:我是否违反了关于 Posix 进程如何以这种方式行事的任何基本假设?如果没有,知道为什么我会看到这样的错误吗?如果是这样,有什么办法可以解决这个问题,并且仍然设法很好地分离 stdout 和 stderr?
我想构建一个正在运行的小脚本,它应该创建一个类似 bash 的会话(在当前的 bash 会话中,创建进程的地方),稍后可以用于一些疯狂的科学(例如管道到浏览器)。
我尝试使用pty.js,管道stdin到bash进程,以及从 bash 会话到stdout流的数据:
var pty = require("pty.js");
var term = pty.spawn('bash', [], {
name: 'xterm-color',
cols: process.stdout.columns,
rows: process.stdout.rows,
cwd: ".",
env: process.env
});
term.pipe(process.stdout);
process.stdin.pipe(term);
term.on("close", function () {
process.exit();
});
Run Code Online (Sandbox Code Playgroud)
这有效,但它非常有问题:

例如,不会捕获非字符(方向键、制表符等)。
我也尝试使用spawn,这还不错,但仍然有问题。
var spawn = require("child_process").spawn;
var bash = spawn("bash");
bash.stdout.pipe(process.stdout);
process.stdin.pipe(bash.stdin);
Run Code Online (Sandbox Code Playgroud)
有没有更好的解决方案如何在 NodeJS 中创建 bash 包装器?
我正在写寻呼机pspg.我必须解决以下问题.读完之后,stdin我应该stdin从之前的阅读管道重新分配到终端阅读.
我用了
freopen("/dev/tty", "r", stdin)
Run Code Online (Sandbox Code Playgroud)
但是,当从命令中使用寻呼机时,它不起作用
su - someuser -c 'export PAGER=pspg psql somedb'
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我收到一个错误:没有这样的设备或地址.
我找到了一个解决方法 - 现在,代码看起来像:
if (freopen("/dev/tty", "r", stdin) == NULL)
{
/*
* try to reopen pty.
* Workaround from:
* https://cboard.cprogramming.com/c-programming/172533-how-read-pipe-while-keeping-interactive-keyboard-c.html
*/
if (freopen(ttyname(fileno(stdout)), "r", stdin) == NULL)
{
fprintf(stderr, "cannot to reopen stdin: %s\n", strerror(errno));
exit(1);
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,检测分配的终端设备的正确方法是什么?
但这种解决方法不正确.它解决了一个问题,但接下来就要来了.当某个用户与当前用户不同时,重新打开失败,并显示" 权限被拒绝"错误.因此,此解决方法不能用于我的目的.
我创建了一个简单的 pty 设置,但是我不确定如何在创建后实际写入主端或从端。我也不确定我的设置是否正确,因为经过检查,pty 的子进程的 Stdin、Stdout 和 Stderr 都是 None 而不是设置为从文件描述符。任何人都可以澄清这是否正确,如果不正确,您对如何解决它有任何建议吗?
use libc::{self};
use nix::pty::openpty;
use std::os::unix::io::FromRawFd;
use std::process::{Child, Command, Stdio};
#[derive(Debug)]
pub struct Pty {
process: Child,
fd: i32,
}
fn create_pty(process: &str) -> Pty {
let ends = openpty(None, None).expect("openpty failed");
let master = ends.master;
let slave = ends.slave;
let mut builder = Command::new(process);
builder.stdin(unsafe { Stdio::from_raw_fd(slave) });
builder.stdout(unsafe { Stdio::from_raw_fd(slave) });
builder.stderr(unsafe { Stdio::from_raw_fd(slave) });
match builder.spawn() {
Ok(process) => {
let pty = Pty {
process,
fd: …Run Code Online (Sandbox Code Playgroud)