AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 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

Substitua o número da captura de expressão regular pela saída de um comando usando esse número no sed

  • 772

Quero traduzir:

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

no seguinte:

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

Gostaria de usar o grupo sed capturando regexp e substituição combinados com o uso do ausyscall aplicado ao número extraído pelo grupo regexp.

Tentei o seguinte no Linux/bash:

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

Imprime: a b c SYSCALL=openat success=yesconforme o esperado.

Então eu tentei usar o grupo de captura #1 como argumento para ausyscall. Assim:

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

Isso invoca ausyscall 1which imprime write. Este não é o grupo capturado #1 (que tem um valor de 257).

Então tentei usar \\1, mas também não funcionou:

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

Isso invoca ausyscall \1, então falha, imprime um erro em stderr( Unknown syscall \1 using x86_64 lookup table) e imprime a b c SYSCALL= success=yesem stdout.

Ele falha ao passar o valor capturado para ausyscall. Tentei com aspas simples, mas a chamada para ausyscall não é feita.

É possível usar sed dessa maneira?

  • Só estou interessado em saber se é esperado que isso seja possível com sed .
  • Sei que isso pode ser feito por outros meios (perl, script python, gawk, etc.), mas quero ver se é possível com sed e se o problema está relacionado a aspas ou algo assim.

É possível com sed ? Se sim, o que estou esquecendo?

sed
  • 5 5 respostas
  • 359 Views

5 respostas

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

    Só estou interessado em saber se é possível fazer isso com o sed.

    Não é esperado que sedpossa fazer isso. Não pode! A execução real do comando é algo que seu shell faz, não sed, então isso não é um recurso de sed, mas outro programa, o shell

    Eu sei que isso poderia ser feito por outros meios (perl, script python, gawk, etc),

    Você já está abordando dessa forma! Você está usando um interpretador de linguagem de script como mecanismo de substituição e, dentro dele, está usando sedpara fazer algumas operações elementares. Seu shell (seja bash, ash, zsh, csh, cmd, …) não é diferente de, digamos, o interpretador python.

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

    O GNU sed pode fazer isso se você estiver disposto a usar a extensão GNU sede para o scomando:

    $ 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
    $ 
    

    A eextensão para sbifurcar um shell e avaliar so espaço de padrões resultante de e substitui o espaço de padrões pelo resultado do comando executado. Para mitigar quaisquer problemas potenciais de injeção de código, o regex para extrair o número do syscall é muito cuidadoso para corresponder apenas a dígitos numéricos. não é usado, pois pode corresponder a outras coisas em vários locais. O número resultante é então passado para um comando [0-9]construído e executado.ausyscall

    O restante dos sedcomandos serve para garantir que, se houver linhas de entrada que não contenham números de chamada de sistema, elas não sejam modificadas.


    Nota lateral - Usuários do Ubuntu podem instalar o ausyscallcomando instalando o auditdpacote:

    sudo apt install auditd
    

    Observe também - sempre que você vir a palavra evaluate, considere isso como um grande aviso de possíveis bugs de injeção de código. Não use comandos como esse em entradas de usuário não verificadas. Como esse caso funciona em dados estritamente numéricos, é simples de validar, mas muito mais cuidado deve ser tomado com casos mais gerais.

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

    Não creio que sedseja possível fazer isso, mas o Perl pode e é apenas um pouco mais complexo:

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

    Embora, isso provavelmente adicionará uma nova linha extra ali que você não quer. Então, você pode precisar disto em vez disso:

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

    O operador do Perl sfunciona praticamente da mesma forma que o do sed. A única diferença aqui é que, ao usar o esinalizador no final ( s:old:new:e), isso nos permite executar código perl no lado da substituição e usar o resultado do código. O código em questão é:

    • `ausyscall $1`: execute ausyscallpassando-o $1(isso é o equivalente ao \1 do sed — embora o Perl também possa trabalhar com \1, mas não com o esinalizador — então é o que foi capturado pelo primeiro conjunto de parênteses) como um argumento. Note que o comando é executado no shell padrão do sistema (geralmente sh).

    • chomp($v=`...`): remove quebras de linha finais. Isso remove a quebra de linha retornada pelo ausyscallcomando. O resultado é armazenado na variável $v.

    • "SYSCALL=$v": isso retorna a saída desejada.

    Note que essa é uma abordagem arriscada. Ela está boa aqui, nesse caso específico, já que você está explicitamente capturando apenas dígitos numéricos, mas, como regra geral, você não quer executar entrada arbitrária como um comando, pois isso o torna vulnerável a um ataque de injeção de código.

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

    Você poderia facilmente usar sedpara traduzir a linha de entrada em um comando shell que seria então capaz de produzir a saída desejada. O evalcomando do shell, combinado com a substituição de comando, deve fazer o truque para processar uma linha de cada vez, como no seu exemplo. Diga, algo assim:

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

    No entanto, como outros responderam, dadas as especificidades da sua aplicação e dependendo de quantas vezes você precisa fazer isso (ou seja, quantas linhas de entrada você deseja processar a qualquer momento), usar ausyscallé provavelmente a maneira menos eficiente e eficaz de fazer isso.

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

    Quero traduzir:

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

    no seguinte:

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

    É isso que a -iopção ausearchfaz (e muito mais):

    -i, --interpret
    Interprete entidades numéricas em texto. Por exemplo, uid é convertido em nome da conta. Se os logs de auditoria não forem enriquecidos, a conversão será feita usando os recursos atuais da máquina onde a pesquisa está sendo executada. Se você renomeou as contas ou não tem as mesmas contas em sua máquina, poderá obter resultados enganosos. Se os logs forem enriquecidos, ele usa os dados suplementares para fazer a conversão. Isso permite relatórios de log precisos, mesmo quando executados em uma máquina diferente daquela de onde os logs originais vieram.

    $ 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
    

    Veja como o número da chamada de sistema foi traduzido, mas também o timestamp¹, arquitetura, modo, uids, gids, alguns argumentos para a chamada de sistema...

    Executar ausyscallpara cada ocorrência de syscall=<numbers>na entrada seria muito ineficiente, especialmente considerando que tanto o GNU sedquanto perlo usado em algumas outras respostas também executam ou podem executar um shell para interpretar o comando. O comando seddo GNU ee eo sinalizador do scomando também são virtualmente impossíveis de usar com segurança, eu recomendo fortemente não usá-lo, nunca.

    Aqui, se você quiser traduzir apenas os números de syscall e não os outros IDs como ausearchfaz, o melhor seria usar a saída de ausyscall --dump(run once) que fornece o mapeamento completo:

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

    Isso pressupõe que você esteja em um sistema de arquitetura única, já que os números de syscall são dependentes da arquitetura. Por exemplo, em um PC moderno onde você pode ter aplicativos rodando em modo x86 ou amd64 (também conhecido como x86_64), isso não funcionará corretamente se houver chamadas de sistema feitas por aplicativos x86, pois ausyscallfornece as traduções para syscalls amd64.

    ausearch -ifaz isso corretamente, mas para fazer o mesmo, você precisaria construir dois mapas, um para x86 e outro para amd64, e extrair a arquitetura do registro de auditoria.

    Exemplo, usando uma compilação estática do busybox x86 aqui:

    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"
    

    Essas são duas openatchamadas de sistema, a primeira sendo a amd64 do cat, a segunda a x86 do busybox-x86.

    ausearch -itraduz corretamente:

    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
    

    Mas o perlcódigo acima está errado (e sua tentativa também):

    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"
    

    Como 295 é o número da preadvchamada de sistema amd64 e da openatchamada de sistema x86.

    Então, nesse sistema multi-arquitetura, eu precisaria de algo como:

    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}->{$&}/'
    

    O que corretamente me dá:

    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"
    

    Se ausyscallnão houver suporte --dump, você pode pelo menos armazenar o resultado em cache para evitar ter que executá-lo várias vezes para o mesmo valor:

    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'
    

    (aqui também lidando com arquiteturas amd64 e x86).


    ¹ usando hora local (usar TZ=UTC0para hora UTC) e formatado como strftime("%x %T"), dependente da localidade; use uma localidade como 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 para obter um registro de data e hora menos ambíguo, semelhante ao ISO8601: sudo TZ=UTC0 LC_ALL= LC_TIME=en_DK.UTF-8 ausearch -i ...; certifique-se de que a localidade esteja disponível no seu sistema, caso contrário, você obterá registros de data e hora no estilo dos EUA da localidade C no %m/%d/%y %H:%M:%Sformato.

    • 0

relate perguntas

  • Linux grep o que no arquivo 1 está no arquivo 2 [duplicado]

  • como grep linhas após a terceira vírgula com condição

  • remova o número de linhas duplicadas com base na correspondência antes da primeira vírgula

  • Como posso melhorar este script de conversão de personagens?

  • Como remover uma única linha entre duas linhas

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve