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 / 791622
Accepted
luator
luator
Asked: 2025-02-25 21:38:28 +0800 CST2025-02-25 21:38:28 +0800 CST 2025-02-25 21:38:28 +0800 CST

Execute o comando em cada linha do arquivo CSV, usando campos em diferentes locais do comando

  • 772

Tenho um arquivo CSV e quero executar um comando para cada linha, usando os campos do arquivo como argumentos separados.

Por exemplo, dado o seguinte arquivo:

foo,42,red
bar,13,blue
baz,27,green

Quero executar os seguintes comandos um após o outro:

my_cmd --arg1 42 --arg2 foo --arg3 red
my_cmd --arg1 13 --arg2 bar --arg3 blue
my_cmd --arg1 27 --arg2 baz --arg3 green

Qual é a maneira mais fácil de conseguir isso? Parece que pode ser possível com xargs, mas não consegui descobrir como exatamente.

shell
  • 5 5 respostas
  • 340 Views

5 respostas

  • Voted
  1. Best Answer
    Marcus Müller
    2025-02-25T22:18:44+08:002025-02-25T22:18:44+08:00

    O GNU parallelpode ler csv diretamente e possui substituição de itens incorporada.

    Mais ou menos retirado diretamente de man parallel:

    parallel --csv 'my_cmd --arg1 {2} --arg2 {1} --arg3 {3}' :::: file.csv
    

    Adicione -j1antes my_cmdpara que essas invocações sejam executadas uma após a outra. Ou não, e faça com que sejam executadas em paralelo.

    (no Debian e Fedora, está no pacote chamado parallel, não em moreutilsou moreutils-parallel)

    Obrigado, Ole Tange!

    • 9
  2. wobtax
    2025-02-25T21:46:42+08:002025-02-25T21:46:42+08:00

    Acho o awk um pouco mais fácil do que mexer no xargs, então costumo montar os argumentos usando o awk e depois passá-los para o xargs:

    $ awk -F ',' '{ print "--arg1", $2, "--arg2", $1, "--arg3", $3 }' csv.txt | xargs -L1 echo
    --arg1 42 --arg2 foo --arg3 red
    --arg1 13 --arg2 bar --arg3 blue
    --arg1 27 --arg2 baz --arg3 green
    

    Aqui -L1diz "execute um comando por linha de entrada".

    • 4
  3. Kusalananda
    2025-02-25T22:03:47+08:002025-02-25T22:03:47+08:00

    O seguinte primeiro usa Miller ( mlr) para converter a entrada CSV sem cabeçalho para a saída JSONL (linhas de objetos JSON únicos). O jqprocessador JSON então lê esses objetos e emite suas partes como argumentos para um comando. A saída é um código shell que pode ser eval-ed.

    $ cat file
    foo,42,red
    bar,13,blue
    baz,27,green
    """mute"" swan","1,23",* * green * *
    
    $ mlr --c2l -N cat file
    {"1": "foo", "2": 42, "3": "red"}
    {"1": "bar", "2": 13, "3": "blue"}
    {"1": "baz", "2": 27, "3": "green"}
    {"1": "\"mute\" swan", "2": "1,23", "3": "* * green * *"}
    
    $ mlr --c2l -N cat file | jq -r '["my_cmd", "--arg1", ."1", "--arg2", ."2", "--arg3", ."3"] | @sh'
    'my_cmd' '--arg1' 'foo' '--arg2' 42 '--arg3' 'red'
    'my_cmd' '--arg1' 'bar' '--arg2' 13 '--arg3' 'blue'
    'my_cmd' '--arg1' 'baz' '--arg2' 27 '--arg3' 'green'
    'my_cmd' '--arg1' '"mute" swan' '--arg2' '1,23' '--arg3' '* * green * *'
    

    O @shoperador output tenta citar os dados fornecidos de uma forma que seria apropriada para um shell. Não é infalível, mas tende a fazer um bom trabalho na maioria das vezes.

    $ eval "$(mlr --c2l -N cat file | jq -r '["my_cmd", "--arg1", ."1", "--arg2", ."2", "--arg3", ."3"] | @sh')"
    zsh: command not found: my_cmd
    zsh: command not found: my_cmd
    zsh: command not found: my_cmd
    zsh: command not found: my_cmd
    
    $ my_cmd () { echo ""; printf 'arg: %s\n' "$@"; }
    $ eval "$(mlr --c2l -N cat file | jq -r '["my_cmd", "--arg1", ."1", "--arg2", ."2", "--arg3", ."3"] | @sh')"
    
    arg: --arg1
    arg: foo
    arg: --arg2
    arg: 42
    arg: --arg3
    arg: red
    
    arg: --arg1
    arg: bar
    arg: --arg2
    arg: 13
    arg: --arg3
    arg: blue
    
    arg: --arg1
    arg: baz
    arg: --arg2
    arg: 27
    arg: --arg3
    arg: green
    
    arg: --arg1
    arg: "mute" swan
    arg: --arg2
    arg: 1,23
    arg: --arg3
    arg: * * green * *
    

    Você também pode executar coisas diretamente do Miller, mas não sei o quão bem sua exec()função lida com valores que precisam ser citados no shell (ou se isso é mesmo um problema). Posso voltar mais tarde e revisar isso quando e se eu tiver tempo para testar isso.

    • 4
  4. jubilatious1
    2025-02-26T04:56:51+08:002025-02-26T04:56:51+08:00

    Usando Raku (anteriormente conhecido como Perl_6)

    ...com o módulo Raku Text::CSV:

    ~$  raku -MText::CSV -e '
    
        my $fh = open "luator.txt", :r;
        my $parser = Text::CSV.new;
    
        until $fh.eof {
              $_ = $parser.getline($fh); 
              run "echo", .[0], .[1], .[2] given $_;
        }
    
        $fh.close;'
    

    Raku é uma linguagem de programação da família Perl que apresenta algumas funções legais para invocar comandos externos. As duas opções são calling shellou calling run. De acordo com a Docs, chamar runé mais seguro.

    Acima, quando você declara o $parserobjeto, você pode definir vários parâmetros, como aceitar um separador sem vírgula (exemplo: my $parser = Text::CSV.new(sep => "|");). Então o arquivo é lido/analisado linha a linha com getline(). Uma saída simples é mostrada acima usando echo.

    Exemplo de entrada:

    ~$ cat luator.txt
    foo,42,red
    bar,13,blue
    baz,27,green
    

    Saída de exemplo (com echo):

    foo 42 red
    bar 13 blue
    baz 27 green
    

    Abaixo, usando run "printf", "%s\t", .[0].uc, .[1], .[2].uc given $_; run "printf", "\n";, separando a saída da coluna com \ttabulações. Note que aqui adicionamos .uca maiúsculas a primeira e a terceira colunas, para mostrar que você ainda pode limpar o texto se precisar (antes de invocar seu my_cmd):

    Saída de exemplo (com printf):

    FOO 42  RED
    BAR 13  BLUE
    BAZ 27  GREEN
    

    Finalmente, você pode tirar arquivos de entrada da linha de comando usando $*ARGFILESa variável dinâmica do Raku. Obviamente, você substituirá seu my_cmdno lugar de printfabaixo:

    ~$ raku -MText::CSV -e '
             my $parser = Text::CSV.new;    
             until $*ARGFILES.eof {
                   $_ = $parser.getline($*ARGFILES); 
             run "printf", "%s ", "--arg1", .[0], "--arg2", .[1], "--arg3", .[2] given $_;
             run "printf", "\n";
       };'   luator.txt
    --arg1 foo --arg2 42 --arg3 red
    --arg1 bar --arg2 13 --arg3 blue
    --arg1 baz --arg2 27 --arg3 green
    

    Caso contrário, veja o primeiro link abaixo para saber como salvar a saída em um objeto "Proc" (processo) do Raku, ou o segundo link abaixo para usar "Proc::Async" (interface de processo assíncrona).

    https://docs.raku.org/type/Proc
    https://docs.raku.org/type/Proc/Async
    https://raku.org

    • 3
  5. Ed Morton
    2025-02-26T21:17:03+08:002025-02-26T21:17:03+08:00

    Separando a seleção/ordenação de campos ( f=...abaixo) da adição --argN(do loop) para que seja fácil modificar campos e/ou ordenar e potencialmente usar o mesmo campo várias vezes, usando any awke um POSIX xargs:

    $ awk -F, -v f='2,1,3' '
        {
            n = split(f, flds)
            for (i = 1; i <= n; i++) {
                printf " --arg%d \"%s\"", i, $(flds[i])
            }
            print ""
        }
    ' file | xargs -L1 echo my_cmd
    my_cmd --arg1 42 --arg2 foo --arg3 red
    my_cmd --arg1 13 --arg2 bar --arg3 blue
    my_cmd --arg1 27 --arg2 baz --arg3 green
    

    Remova echoquando terminar o teste.

    Dado que, alterar a ordem e duplicar campos é tão simples quanto alterar f='...':

    $ awk -F, -v f='3,1,3,2,1' '
        {
            n = split(f, flds)
            for (i = 1; i <= n; i++) {
                printf " --arg%d \"%s\"", i, $(flds[i])
            }
            print ""
        }
    ' file | xargs -L1 echo my_cmd
    my_cmd --arg1 red --arg2 foo --arg3 red --arg4 42 --arg5 foo
    my_cmd --arg1 blue --arg2 bar --arg3 blue --arg4 13 --arg5 bar
    my_cmd --arg1 green --arg2 baz --arg3 green --arg4 27 --arg5 baz
    

    Os \"s ao redor %ssão para garantir que xargsos campos que contêm espaços sejam manipulados corretamente, caso contrário, um campo como a bseria dividido em 2 argumentos separados para my_cmd.

    • 0

relate perguntas

  • Como funciona este comando? mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc -l 1234 > /tmp/f

  • FreeBSD's sh: funções de lista

  • Existe uma maneira de fazer ls mostrar arquivos ocultos apenas para determinados diretórios?

  • o que grep -v grep faz

  • Como salvar um caminho com ~ em uma variável?

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