AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 785920
Accepted
PRouleau
PRouleau
Asked: 2024-10-31 22:17:55 +0800 CST2024-10-31 22:17:55 +0800 CST 2024-10-31 22:17:55 +0800 CST

将正则表达式捕获的数字替换为 sed 中使用该数字的命令的输出

  • 772

我想要翻译:

  • "a b c syscall=257 success=yes"

改为:

  • "a b c syscall=openat success=yes"

我喜欢使用sed组捕获正则表达式和替换,并结合使用 ausyscall 应用于正则表达式组提取的数字。

我在 Linux/bash 下尝试了以下操作:

echo "a b c  syscall=257 success=yes" |
   sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall 257)":"

它打印:a b c SYSCALL=openat success=yes正如预期的那样。

然后我尝试使用捕获组 #1 作为 的参数ausyscall。像这样:

echo "a b c  syscall=257 success=yes" | 
   sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall \1)":"

这将调用ausyscall 1which 打印write。这不是捕获的组 #1(其值为 257)。

因此我尝试使用\\1,但也失败了:

echo "a b c  syscall=257 success=yes" | 
   sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall \\1)":"

这将调用失败,在 stderr( )ausyscall \1上打印错误并在 stdout 上打印。Unknown syscall \1 using x86_64 lookup tablea b c SYSCALL= success=yes

无法将捕获的值传递给 ausyscall。我尝试使用单引号,但无法调用 ausyscall。

可以这样使用sed吗?

  • 我只想知道是否能够用sed来做到这一点。
  • 我知道可以通过其他方式(perl、python 脚本、gawk 等)来完成,但我想看看是否可以用 sed 来完成,以及问题是否与引用或类似的东西有关。

使用sed可以实现吗?如果可以,我遗漏了什么?

sed
  • 5 5 个回答
  • 359 Views

5 个回答

  • Voted
  1. Marcus Müller
    2024-10-31T22:38:07+08:002024-10-31T22:38:07+08:00

    我只想知道是否能够用 sed 来做到这一点。

    预计 不会sed执行此操作。它不能!命令的实际运行是您的 shell 执行的,而不是sed,因此这不是 的功能sed,而是另一个程序,即 shell

    我知道可以用其他方法(perl、python 脚本、gawk 等)来完成,

    您已经以这种方式开始操作了!您正在使用脚本语言解释器作为替换引擎,并在其中执行sed一些基本操作。您的 shell(无论是 bash、ash、zsh、csh、cmd 等)与 python 解释器没有什么不同。

    • 4
  2. Best Answer
    Digital Trauma
    2024-11-01T08:54:48+08:002024-11-01T08:54:48+08:00

    如果您愿意使用GNU sed扩展命令, GNU sed可以做到这一点:es

    $ echo "a b c  syscall=257 success=yes" |
        sed -E "
          h         # copy input line from pattern space to hold space
          s/^.*syscall=([0123456789]+).*$/ausyscall \1/e   # get just the syscall number
          t match   # Conditionally jump to "match" label if above substitution succeeded
          x         #   else revert pattern space back to original input
          b end     #   and jump to "end" label
          :match
          G         # append newline + hold space to pattern space
          s/^([^\n]+)\n(.*syscall=)[0123456789]+(.*)$/\2\1\3/  # replace number with syscall name
          :end
    "
    a b c  syscall=openat success=yes
    $ 
    

    扩展e派生s一个 shell 并评估s的结果模式空间,并用执行命令的结果替换模式空间。为了减轻任何潜在的代码注入问题,提取系统调用号的正则表达式非常小心,只匹配数字。 [0-9]不使用,因为它可以匹配各种语言环境中的其他内容。然后将结果数字传递给构造的ausyscall命令并执行。

    其余命令sed是为了确保如果输入行不包含系统调用号,则它们将保持不变。


    附注-Ubuntu 用户可以通过安装软件包来安装ausyscall命令auditd:

    sudo apt install auditd
    

    还要注意 - 每当您看到 这个词时evaluate,请将其视为可能存在代码注入错误的重大警告。 不要对未经审查的用户输入使用此类命令。 由于这种情况适用于严格的数字数据,因此很容易验证,但对于更一般的情况,必须更加小心。

    • 4
  3. terdon
    2024-11-01T00:06:26+08:002024-11-01T00:06:26+08:00

    我不认为sed可以做到这一点,但是 perl 可以,而且只是稍微复杂一些:

    echo "a b c  syscall=257 success=yes" |
      perl -pe 's:syscall=(\d+):"SYSCALL=" . `ausyscall $1`:e'
    

    不过,这很可能会在那里添加一个你不想要的额外换行符。因此,你可能需要这样做:

    echo "a b c  syscall=257 success=yes" |
      perl -pe 's:syscall=(\d+):chomp($v=`ausyscall $1`); "SYSCALL=$v" :e'
    

    Perls运算符的工作方式与 sed 运算符基本相同。这里唯一的区别是,通过e在末尾使用标志 ( s:old:new:e),我们可以在替换端运行 perl 代码,并使用代码的结果。所讨论的代码是:

    • `ausyscall $1`:运行ausyscall并传递它$1(这相当于 sed 的 \1 — 尽管 Perl 也可以使用 \1,只是不能使用e标志 — 因此它是第一组括号捕获的内容)作为参数。请注意,该命令在系统的默认 shell 中运行(通常是sh)。

    • chomp($v=`...`):删除尾随换行符。这将删除命令返回的换行符ausyscall。结果存储在变量中$v。

    • "SYSCALL=$v":这将返回所需的输出。

    请注意,这是一种有风险的方法。在这种特定情况下,这种方法是可行的,因为您明确只捕获数字,但一般来说,您不想将任意输入作为命令执行,因为这会使您容易受到代码注入攻击。

    • 3
  4. Greg A. Woods
    2024-11-03T01:59:44+08:002024-11-03T01:59:44+08:00

    您可以轻松地使用sed将输入行转换为 shell 命令,然后该命令将能够产生所需的输出。shell 的eval命令与命令替换相结合,应该可以一次处理一行,如您的示例所示。例如,像这样:

    echo "a b c  syscall=257 success=yes" | \
      eval $(sed -e 's/^/echo "/' \
                 -e 's/syscall=\([0-9]*\)/syscall=$(ausyscall \1)/' \
                 -e 's/$/"/')
    

    但是正如其他人所回答的那样,考虑到您的应用程序的具体情况,并且取决于您需要执行多少次(即,您想在任何给定时间处理多少行输入),使用ausyscall可能是效率最低、最不有效的方法。

    • 1
  5. Stéphane Chazelas
    2024-11-01T19:32:30+08:002024-11-01T19:32:30+08:00

    我想要翻译:

    • "a b c syscall=257 success=yes"

    改为:

    • "a b c syscall=openat success=yes"

    这就是-i选项的ausearch作用(以及更多):

    -i,--interpret
    将数字实体解释为文本。例如,uid 转换为帐户名称。如果审计日志未丰富,则使用运行搜索的计算机的当前资源进行转换。如果您重命名了帐户,或者计算机上没有相同的帐户,则可能会得到误导性的结果。如果日志丰富,它会使用补充数据进行转换。即使在与原始日志不同的计算机上运行,​​也可以实现准确的日志报告。

    $ sudo ausearch -k a
    time->Fri Nov  1 11:28:13 2024
    type=PROCTITLE msg=audit(1730460493.172:119): proctitle=6361740061
    type=PATH msg=audit(1730460493.172:119): item=0 name="a" inode=5504724 dev=00:2b mode=0100775 ouid=1000 ogid=1000 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
    type=CWD msg=audit(1730460493.172:119): cwd="/home/chazelas"
    type=SYSCALL msg=audit(1730460493.172:119): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=7ffe02333e53 a2=0 a3=0 items=1 ppid=15215 pid=23968 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts2 ses=3 comm="cat" exe="/usr/bin/cat" subj=unconfined key="a"
    
    $ sudo ausearch -k a -i
    type=PROCTITLE msg=audit(01/11/24 11:28:13.172:119) : proctitle=cat a
    type=PATH msg=audit(01/11/24 11:28:13.172:119) : item=0 name=a inode=5504724 dev=00:2b mode=file,775 ouid=chazelas ogid=chazelas rdev=00:00 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
    type=CWD msg=audit(01/11/24 11:28:13.172:119) : cwd=/home/chazelas
    type=SYSCALL msg=audit(01/11/24 11:28:13.172:119) : arch=x86_64 syscall=openat success=yes exit=3 a0=AT_FDCWD a1=0x7ffe02333e53 a2=O_RDONLY a3=0x0 items=1 ppid=15215 pid=23968 auid=chazelas uid=chazelas gid=chazelas euid=chazelas suid=chazelas fsuid=chazelas egid=chazelas sgid=chazelas fsgid=chazelas tty=pts2 ses=3 comm=cat exe=/usr/bin/cat subj=unconfined key=a
    

    查看系统调用号是如何转换的,还有时间戳¹、arch、模式、uids、gids,以及系统调用的一些参数...

    对输入中ausyscall出现的每次运行都会非常低效,尤其是考虑到 GNU和(如在其他一些答案中所使用的)也运行或可能运行 shell 来解释命令。 GNU的命令和命令标志实际上也不可能安全使用,我强烈建议永远不要使用它。syscall=<numbers>sedperlsedees

    在这里,如果您只想翻译系统调用号而不是其他 ID ausearch,那么最好使用ausyscall --dump(运行一次)的输出,它会给您完整的映射:

    sudo ausearch... | perl -pe '
      BEGIN {%map = split " ", qx{ausyscall --dump}}
      s/^type=SYSCALL.*? syscall=\K\d+/$map{$&}/'
    

    这假设您使用的是单架构系统,因为系统调用编号与架构有关。例如,在现代 PC 上,您可以让应用程序以 x86 或 amd64(又名 x86_64)模式运行,但如果 x86 应用程序进行系统调用,则无法正常工作,因为系统会ausyscall为您提供 amd64 系统调用的转换。

    ausearch -i可以正确地完成此操作,但要做同样的事情,您需要构建两个映射,一个用于 x86,一个用于 amd64,并从审计记录中提取体系结构。

    例如,此处使用 x86 busybox 的静态构建:

    type=SYSCALL msg=audit(1730460493.172:119): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=7ffe02333e53 a2=0 a3=0 items=1 ppid=15215 pid=23968 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts2 ses=3 comm="cat" exe="/usr/bin/cat" subj=unconfined key="a"
    type=SYSCALL msg=audit(1730462981.012:250): arch=40000003 syscall=295 success=yes exit=3 a0=ffffff9c a1=ffdcce69 a2=8000 a3=0 items=1 ppid=27309 pid=27411 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts11 ses=3 comm="busybox-x86" exe="/home/chazelas/busybox-x86" subj=unconfined key="a"
    

    这是 2 个openat系统调用,第一个是 amd64 系统调用cat,第二个是 busybox-x86 系统调用。

    ausearch -i正确翻译如下:

    type=SYSCALL msg=audit(01/11/24 11:28:13.172:119) : arch=x86_64 syscall=openat success=yes exit=3 a0=AT_FDCWD a1=0x7ffe02333e53 a2=O_RDONLY a3=0x0 items=1 ppid=15215 pid=23968 auid=chazelas uid=chazelas gid=chazelas euid=chazelas suid=chazelas fsuid=chazelas egid=chazelas sgid=chazelas fsgid=chazelas tty=pts2 ses=3 comm=cat exe=/usr/bin/cat subj=unconfined key=a
    type=SYSCALL msg=audit(01/11/24 12:09:41.012:250) : arch=i386 syscall=openat success=yes exit=3 a0=AT_FDCWD a1=0xffdcce69 a2=O_RDONLY a3=0x0 items=1 ppid=27309 pid=27411 auid=chazelas uid=chazelas gid=chazelas euid=chazelas suid=chazelas fsuid=chazelas egid=chazelas sgid=chazelas fsgid=chazelas tty=pts11 ses=3 comm=busybox-x86 exe=/home/chazelas/busybox-x86 subj=unconfined key=a
    

    但是perl上面的代码是错误的(你的尝试也是如此):

    type=SYSCALL msg=audit(1730460493.172:119): arch=c000003e syscall=openat success=yes exit=3 a0=ffffff9c a1=7ffe02333e53 a2=0 a3=0 items=1 ppid=15215 pid=23968 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts2 ses=3 comm="cat" exe="/usr/bin/cat" subj=unconfined key="a"
    type=SYSCALL msg=audit(1730462981.012:250): arch=40000003 syscall=preadv success=yes exit=3 a0=ffffff9c a1=ffdcce69 a2=8000 a3=0 items=1 ppid=27309 pid=27411 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts11 ses=3 comm="busybox-x86" exe="/home/chazelas/busybox-x86" subj=unconfined key="a"
    

    因为 295 是 amd64 系统调用的编号preadv,也是openatx86 系统调用的编号。

    因此,在那个多架构系统上,我需要类似这样的东西:

    sudo ausearch... | perl -pe '
      BEGIN {
        %{$map{"c000003e"}} = split " ", qx{ausyscall --dump b64};
        %{$map{"40000003"}} = split " ", qx{ausyscall --dump b32};
      }
      s/^type=SYSCALL.*? arch=(\S+) syscall=\K\d+/$map{$1}->{$&}/'
    

    这正确地给了我:

    type=SYSCALL msg=audit(1730460493.172:119): arch=c000003e syscall=openat success=yes exit=3 a0=ffffff9c a1=7ffe02333e53 a2=0 a3=0 items=1 ppid=15215 pid=23968 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts2 ses=3 comm="cat" exe="/usr/bin/cat" subj=unconfined key="a"
    type=SYSCALL msg=audit(1730462981.012:250): arch=40000003 syscall=openat success=yes exit=3 a0=ffffff9c a1=ffdcce69 a2=8000 a3=0 items=1 ppid=27309 pid=27411 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts11 ses=3 comm="busybox-x86" exe="/home/chazelas/busybox-x86" subj=unconfined key="a"
    

    如果ausyscall不支持--dump,您至少可以缓存结果,以避免对相同的值运行多次:

    sudo ausearch... | perl -pe '
      BEGIN {%arch = qw(c000003e b64 40000003 b32)}
      s{^type=SYSCALL.*? arch=(\d+) syscall=\K\d+}{
        $cache{$1}->{$&} //= eval {
          $name = `ausyscall $arch{$1} $&`;
          chomp $name;
          $name;
        }
      }e'
    

    (这里还处理 amd64 和 x86 架构)。


    ¹ 使用当地时间(用于TZ=UTC0UTC 时间)并格式化为strftime("%x %T"),依赖于语言环境;使用诸如 csb_PL de_AT de_BE de_LU en_CA en_DK eo fr_CA hu_HU kv_RU lt_LT se_NO si_LK sv_SE wae_CH 之类的语言环境来获取不太模糊的 ISO8601 类时间戳:sudo TZ=UTC0 LC_ALL= LC_TIME=en_DK.UTF-8 ausearch -i ...;确保您的系统上可以使用该语言环境,否则您将从 C 语言环境获得美国风格的时间戳%m/%d/%y %H:%M:%S格式。

    • 0

相关问题

  • Linux grep文件1中的内容在文件2中[重复]

  • 如何在第三个逗号后用条件grep行

  • 根据第一个逗号之前的匹配删除重复行数

  • 如何改进这个字符转换脚本?

  • 如何删除两行之间的单行

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve