【问题标题】:Capturing bash history of piped scripts from within Perl or Ruby?从 Perl 或 Ruby 中捕获管道脚本的 bash 历史?
【发布时间】:2013-09-25 11:11:08
【问题描述】:

如果我在 bash shell 中运行此命令:

script1 -i foo | script2 -i bar | script3 -i foobar

是否有一种可靠的方法来获取该命令,因为它会出现在 script1-3 中的 bash_history 中?

据我所知,从 .bash_history 文件中获取信息是行不通的,因为写入该文件是缓冲的,因此可能不同步。

【问题讨论】:

  • 从技术上讲,那里有三个命令,放在一起形成一个管道。每个脚本都可以从 argv 中恢复自己的命令,虽然只能以最终处理的形式(即扩展变量、拆分单词、删除引号等),但无法获取整个管道。正如您所说,历史记录文件是无用的(不是因为写入缓冲如此之多,而是写入只是偶尔进行,尽管您可以使历史写入更具侵略性。)
  • 也许有办法挂钩到 bash 历史缓冲区?显然,脚本需要与 shell 交互才能获取信息。
  • 嗯,可以设置一个环境变量来确保历史缓冲区的刷新:export PROMPT_COMMAND='history -a'。那么是否可以从 .bash_history 获取信息?
  • 你当然可以试试。 (但一次只能在一个 shell 中,除非您为每个会话创建单独的历史文件。)
  • 嗯,我真的需要这个来处理多个会话。也可以在会话之间同步历史记录:export PROMPT_COMMAND='history -a; history -r' - 但我担心竞争条件。

标签: ruby perl bash pipe


【解决方案1】:

您可以将操作系统级别的跟踪器附加到您的程序,然后查找exec 系统调用。

那些通过外壳的显示为["sh", "-c", "$cmd"]$cmd 就是你要找的。​​p>

例如,在 Linux 上,使用 strace:

#!/usr/bin/perl

my $parent = $$;
my $pid = fork;

unless ($pid) {
    defined $pid or die "fork failed: $!\n";
    open STDOUT, '>&STDERR'; # redirect stdout to stderr
    do { exec('strace',
              -p => $parent,
              -e => 'trace=clone,execve',
              -e => 'signal=none',
              -s => 32000,
              -b => 'execve',
              '-f', '-qq') };
    warn "exec failed: $!\n";
    POSIX::_exit(1);
}

sleep 2; # wait for strace to attach to me

system 'ls $HOME';
system 'echo /*';

END {
    kill TERM => $pid;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 2014-03-02
    • 2010-11-09
    相关资源
    最近更新 更多