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 / computer / Perguntas / 1425158
Accepted
Brian
Brian
Asked: 2019-04-14 13:40:32 +0800 CST2019-04-14 13:40:32 +0800 CST 2019-04-14 13:40:32 +0800 CST

script bash: saída de eco truncada e na ordem errada

  • 772

Estou tendo um problema com um script bash que está ecoando a saída em uma ordem inesperada. O roteiro é o seguinte. O problema está na saída das linhas 30-32.


1 IFS=$'\n'
2 i=1
3 bluered=""
4 blueyellow=""
5 redyellow=""
6 all=""
7 while [ $i -le `cat sorted.csv | wc -l` ]
8       do
9           for j in {0..2}
10               do
11                     # cat sorted.csv | head -$i | tail -1 | awk -F',' '{print $1}'
12                     declare "`cat sorted.csv | head -$i | tail -1 | awk -F',' '{print $1}'`=`cat sorted.csv | head -$i | tail -1 | awk -F','   '{print $5}'`"
13                     i=$((i+1))
14               done
15
16           if [[ ${blue} == ${red} ]]; then bluered=1; else bluered=0; fi
17           if [[ ${blue} == ${yellow} ]]; then blueyellow=1; else blueyellow=0; fi
18           if [[ ${red} == ${yellow} ]]; then redyellow=1; else redyellow=0; fi
19           if [[ ${blue} == ${red} ]] && [[ ${red} == ${yellow} ]]; then all=1; else all=0; fi
20
21           echo "`cat sorted.csv | head -$((i-3)) | tail -1`"
22           echo ",$all,$bluered,$blueyellow,$redyellow"
23           echo "`cat sorted.csv | head -$((i-2)) | tail -1`"
24           echo ",$all,$bluered,$blueyellow,$redyellow"
25           echo "`cat sorted.csv | head -$((i-1)) | tail -1`"
26           echo ",""$all"",""$bluered"",""$blueyellow"",""$redyellow"
27
28
29
30           echo  "`cat sorted.csv | head -$((i-3)) | tail -1`,$all,$bluered,$blueyellow,$redyellow"
31           echo  "`cat sorted.csv | head -$((i-2)) | tail -1`"",$all,$bluered,$blueyellow,$redyellow"
32           echo  "`cat sorted.csv | head -$((i-1)) | tail -1`"",""$all"",""$bluered"",""$blueyellow"",""$redyellow"
33       done

As linhas 30-32 têm uma formatação de aspas duplas ligeiramente diferente, pois eu estava tentando coisas diferentes para que funcionasse corretamente. As linhas 21-26 nada mais são do que as linhas 30-32 decompostas em 2 partes (ou seja, a linha 21-22 é igual à linha 30).

Com base no arquivo de entrada, "sorted.csv", a saída correta das linhas 30-32 (para as primeiras 3 linhas do arquivo de entrada) deve ser:

blue,1,WCC131035882,0,e89d89d7ca7c502ca8d3b2e0d7c4980dba346a63d57a437d8f1428065fb83e9f,0,0,0,1
red,1,Z292V5DB,0,68a4917c878f1b26e370264097f476840aa995dc6b8d6d2e552a78a6bdd77c68,0,0,0,2
yellow,1,Z292V94K,0,68a4917c878f1b26e370264097f476840aa995dc6b8d6d2e552a78a6bdd77c68,0,0,0,1

mas a saída real é:

,0,0,0,1CC131035882,0,e89d89d7ca7c502ca8d3b2e0d7c4980dba346a63d57a437d8f1428065fb83e9f #(line 30 output)
,0,0,0,192V5DB,0,68a4917c878f1b26e370264097f476840aa995dc6b8d6d2e552a78a6bdd77c68 #(line 31 output)
,0,0,0,1,Z292V94K,0,68a4917c878f1b26e370264097f476840aa995dc6b8d6d2e552a78a6bdd77c68 #(line 32 output)

As linhas 21 a 26 retornam a seguinte saída:

blue,1,WCC131035882,0,e89d89d7ca7c502ca8d3b2e0d7c4980dba346a63d57a437d8f1428065fb83e9f #(line 21 output)
,0,0,0,1 #(line 22 output)   
red,1,Z292V5DB,0,68a4917c878f1b26e370264097f476840aa995dc6b8d6d2e552a78a6bdd77c68 #(line 23output)
,0,0,0,1 #(line 24 output)
yellow,1,Z292V94K,0,68a4917c878f1b26e370264097f476840aa995dc6b8d6d2e552a78a6bdd77c68 #(line 25)
,0,0,0,1 #(line 26 output)

Resumindo, quero concatenar a saída das linhas 21-22, 23-24 e 25-26 usando 3 comandos de linha única, como as linhas 30-32 (mas com a sintaxe correta). Observe que as linhas 21-26 estão incluídas apenas em o script para demonstrar que as duas partes da linha 30 (31 ou 32) estão funcionando corretamente quando separadas em duas linhas. Atualmente, a linha 30 concatena efetivamente a saída da linha 22 e depois da linha 21 em vez de 21 e depois 22. No entanto, ao fazer essa concatenação reversa, ela também trunca os primeiros 8 caracteres da saída da linha 21 (observe, a saída da linha 22 tem exatamente 8 caracteres).

Como escrevo corretamente as linhas 30-32 para que criem a saída desejada?

Agradecemos antecipadamente por sua ajuda.

linux bash script
  • 2 2 respostas
  • 2009 Views

2 respostas

  • Voted
  1. Best Answer
    Kamil Maciorowski
    2019-04-14T17:30:28+08:002019-04-14T17:30:28+08:00

    Mais perspicácia do que um "uso" lacônico dos2unix.

    Aparentemente sorted.csvusa terminações de linha CR+LF enquanto deveria usar apenas LF .

    Quando você usa `something`avanços de linha (LF) no final da saída something, são removidos, mas não retornos de carro (CR). No seu caso text+CR+LFtornou -se text+CR. Se for uma única entrada para echo, a ferramenta adiciona uma nova linha como de costume e, novamente, você tem CR+LF no final. Ao imprimir no console, este CR não muda nada.

    Mas, no caso do echo "`foo`bar"caractere CR retornado por fooficar no meio da string resultante, qualquer coisa que vier a seguir será impressa na borda esquerda do console, sobrescrevendo a parte anterior.

    A solução é usar dos2unix sorted.csv, como você já observou .


    Mas há mais:

    • Uso inútil decat
    • Qual é a diferença entre $(stuff)e `stuff`?
    • Por que é printfmelhor do que echo?
    • Muitas aparições de ""(por exemplo, na linha 32) não fazem nada. Eles estão fechando+abrindo, não abrindo+fechando. Eles apenas ofuscam o código. Eu entendo que eles são "experimentais" e estou dizendo claramente que eles não mudam nada.

    E talvez

    • O que há de errado com echo $(stuff)ou echo `stuff`?

      Admito que esta objeção é questionável aqui. "`foo`bar"é útil retirar qualquer LF à direita da saída de fooe concatená-lo com bar; no seu caso é importante. Então a sintaxe como echo "`foo`"foi usada para demonstrar a diferença relevante no comportamento, você afirmou isso explicitamente.


    dos2unixcertamente não responde à pergunta, que é [ênfase minha]:

    Como escrevo corretamente as linhas 30-32 para que criem a saída desejada?

    Uma linha 32 escrita corretamente usaria pelo menos printf, no cat. Crases e aspas excessivas podem permanecer, embora o código seja mais legível com $( … )citações razoáveis. Você também pode considerar separar o formato dos dados, é fácil com printf:

    printf '%s,%s,%s,%s,%s\n' "$( <sorted.csv head -$((i-1)) | tail -1 )" "$all" "$bluered" "$blueyellow" "$redyellow"
    

    Além disso, existem soluções ruins em outros lugares:

    • while [ $i -le `cat sorted.csv | wc -l` ](além de cate backticks). Não há necessidade de obter o número de linhas a cada iteração. wc -l sorted.csvdeve ser executado uma vez antes do loop, seu resultado armazenado em uma variável (a menos que você espere que o número de linhas mude durante a execução, mas acho que não; a lógica do script faz mais sentido se o número não mudar ).

    • Você lê o arquivo de novo e de novo. Quanto mais linhas houver, mais vezes você reabrirá, lerá desde o início e escolherá uma única linha de cada vez. O fluxo deve ser reprojetado para que o arquivo seja analisado linha por linha, possivelmente sem o anterior wc -l, possivelmente de maneira semelhante a um canal (ou seja, aberto apenas uma vez, lido apenas uma vez sem pular para trás). Já que você usa o declarebuiltin, while IFS= read -r … ; done <sorted.csvprovavelmente é obrigatório (talvez com preliminar awk, por exemplo <sorted.csv awk … | while IFS= read -r …). Você pode readtrês vezes para três variáveis ​​diferentes e, em seguida, executar operações; então leia as próximas três linhas.readem si é ineficiente, mas é mais elegante do que reabrir o arquivo várias vezes. Observe que seu script se torna menos eficiente a cada linha adicional no arquivo; se o arquivo for grande o suficiente para que a ineficiência readse manifeste, sua abordagem provavelmente terá um desempenho ainda pior.

      Toda essa mudança, se você aceitar, não será trivial.

    • O nome do arquivo não deve ser codificado em tantos lugares. Ler o arquivo apenas uma vez reduziria naturalmente esse problema. Mesmo assim é bom começar input_file="sorted.csv"e usar "$input_file"sempre que precisar. Se você decidir passar o caminho do arquivo como um argumento de linha de comando, será tão fácil quanto digitar input_file="$1".

    • Por que não há shebang?

    Considerando o quadro geral, as linhas 30-32 mais corretas seriam como neste trecho:

    #!/bin/bash
    input_file="sorted.csv
    …
    while IFS= read -r pre_previous_line && IFS= read -r previous_line && IFS= read -r current_line; do
       …
       # useful bashism instead of    echo "$previous_line" | some_command
       some_command <<< "$previous_line"
       …
       # printf will reuse the format if there are more arguments than the format needs
       # so this one line will be enough for your three
       # (split for readability, it's still one line for the shell)
       printf '%s,%s,%s,%s,%s\n' \
          "$pre_previous_line" "$all" "$bluered" "$blueyellow" "$redyellow" \
          "$previous_line"     "$all" "$bluered" "$blueyellow" "$redyellow" \
          "$current_line"      "$all" "$bluered" "$blueyellow" "$redyellow"
       …
    done <"$input_file"
    

    Provavelmente o único awktrabalho como filtro pode fazer isso; o arquivo seria canalizado para ele. Em awkvocê pode armazenar informações em variáveis ​​também, para usá-las posteriormente. Condicionais também estão disponíveis. Algo como este exemplo mal testado :

    #!/usr/bin/awk -f
    BEGIN { FS="," }
    {
    if ($1 == "blue") blue=$5
    if ($1 == "red") red=$5
    if ($1 == "yellow") yellow=$5
    if (NR%3 == 1) prepre=$0
    if (NR%3 == 2) pre=$0
    if (NR%3 == 0)
       {
       bluered=($blue == $red)
       blueyellow=($blue == $yellow)
       redyellow=($red == $yellow)
       all= bluered * blueyellow
       suffix=","all","bluered","blueyellow","redyellow
       print prepre suffix
       print pre    suffix
       print $0     suffix
       }
    }
    

    (Nota: awktestei com is de fato mawk). Salve-o, torne-o executável, canalize seu sorted.csvpara ele (por exemplo, <sorted.csv ./the_script).

    • 2
  2. Brian
    2019-04-14T14:51:01+08:002019-04-14T14:51:01+08:00

    O comentário sobre retornos de carro estar no arquivo foi direto. Depois de executar o arquivo de entrada pensado dox2unix, o script foi executado conforme o esperado. Obrigado, Gordon.

    • 0

relate perguntas

  • Notificar-enviar notificações aparecendo na janela

  • execute o contêiner do docker como root

  • Como ativar o sensor de impressão digital no domínio e no diretório ativo do Linux

  • Como alterar permanentemente Ctrl + C para Ctrl + K no CentOS 7?

  • como abrir um arquivo de escritório do WSL

Sidebar

Stats

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

    O visualizador de fotos do Windows não pode ser executado porque não há memória suficiente?

    • 5 respostas
  • Marko Smith

    Como faço para ativar o WindowsXP agora que o suporte acabou?

    • 6 respostas
  • Marko Smith

    Área de trabalho remota congelando intermitentemente

    • 7 respostas
  • Marko Smith

    Serviço do Windows 10 chamado AarSvc_70f961. O que é e como posso desativá-lo?

    • 2 respostas
  • Marko Smith

    O que significa ter uma máscara de sub-rede /32?

    • 6 respostas
  • Marko Smith

    Ponteiro do mouse movendo-se nas teclas de seta pressionadas no Windows?

    • 1 respostas
  • Marko Smith

    O VirtualBox falha ao iniciar com VERR_NEM_VM_CREATE_FAILED

    • 8 respostas
  • Marko Smith

    Os aplicativos não aparecem nas configurações de privacidade da câmera e do microfone no MacBook

    • 5 respostas
  • Marko Smith

    ssl.SSLCertVerificationError: falha na verificação do certificado [SSL: CERTIFICATE_VERIFY_FAILED]: não foi possível obter o certificado do emissor local (_ssl.c:1056)

    • 4 respostas
  • Marko Smith

    Como posso saber em qual unidade o Windows está instalado?

    • 6 respostas
  • Martin Hope
    Albin Como faço para ativar o WindowsXP agora que o suporte acabou? 2019-11-18 03:50:17 +0800 CST
  • Martin Hope
    fixer1234 O "HTTPS Everywhere" ainda é relevante? 2019-10-27 18:06:25 +0800 CST
  • Martin Hope
    Kagaratsch O Windows 10 exclui muitos arquivos minúsculos muito lentamente. Algo pode ser feito para agilizar? 2019-09-23 06:05:43 +0800 CST
  • Martin Hope
    andre_ss6 Área de trabalho remota congelando intermitentemente 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney Por que colocar um ponto após o URL remove as informações de login? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension Ponteiro do mouse movendo-se nas teclas de seta pressionadas no Windows? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    Inter Sys Como Ctrl+C e Ctrl+V funcionam? 2019-05-15 02:51:21 +0800 CST
  • Martin Hope
    jonsca Todos os meus complementos do Firefox foram desativados repentinamente, como posso reativá-los? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK É possível criar um código QR usando texto? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 Altere o nome da ramificação padrão do git init 2019-04-01 06:16:56 +0800 CST

Hot tag

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

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