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 / 490524
Accepted
don_crissti
don_crissti
Asked: 2018-12-23 12:44:21 +0800 CST2018-12-23 12:44:21 +0800 CST 2018-12-23 12:44:21 +0800 CST

Por que o awk para e espera se o nome do arquivo contém = e como contornar isso?

  • 772
awk 'processing_script_here' my=file.txt

parece parar e esperar indefinidamente...
O que está acontecendo aqui e como faço para que funcione?

awk filenames
  • 3 3 respostas
  • 1999 Views

3 respostas

  • Voted
  1. Chris Down
    2018-12-23T12:53:36+08:002018-12-23T12:53:36+08:00

    Na maioria das versões do awk, os argumentos após a execução do programa são:

    1. Um arquivo
    2. Uma atribuição do formuláriox=y

    Como seu nome de arquivo está sendo interpretado como caso #2, o awk ainda está esperando que algo seja lido em stdin (já que ele não percebe que algum nome de arquivo foi passado).

    Portátil, esse comportamento está documentado em POSIX :

    Qualquer um dos dois tipos de argumento a seguir pode ser misturado:

    • file: Um nome de caminho de um arquivo que contém a entrada a ser lida, que corresponde ao conjunto de padrões no programa. Se nenhum operando de arquivo for especificado, ou se um operando de arquivo for '-', a entrada padrão deve ser usada.
    • atribuição: Um operando que começa com um sublinhado ou caractere alfabético do conjunto de caracteres portátil (consulte a tabela no volume Definições de Base do IEEE Std 1003.1-2001, Seção 6.1, Conjunto de Caracteres Portáteis), seguido por uma sequência de sublinhados, dígitos, e alfabética do conjunto de caracteres portátil, seguido pelo caractere '=', deve especificar uma atribuição de variável em vez de um nome de caminho.

    Como tal, portátilmente, você tem algumas opções (o nº 1 é provavelmente o menos intrusivo):

    1. Use awk ... ./my=file, que evita isso, pois .não é "um sublinhado ou caractere alfabético do conjunto de caracteres portátil".
    2. Coloque o arquivo em stdin usando awk ... < my=file. No entanto, isso não funciona bem com vários arquivos.
    3. Faça um hardlink para o arquivo temporariamente e use-o. Você pode fazer algo como ln my=file my_file, e depois usar my_filenormalmente. Nenhuma cópia será executada e ambos os arquivos serão apoiados pelos mesmos dados e metadados do inode. Depois de usá-lo, é seguro remover o link criado, pois o número de referências ao inode ainda será maior que 0.
    • 22
  2. Best Answer
    Stéphane Chazelas
    2018-12-23T14:34:03+08:002018-12-23T14:34:03+08:00

    Como diz Chris , os argumentos do formulário variablename=anythingsão tratados como atribuição de variáveis ​​(que são executadas no momento em que os argumentos são processados ​​em oposição aos (mais recentes) -v var=valueque são executados antes das BEGINinstruções) em vez de nomes de arquivos de entrada.

    Isso pode ser útil em coisas como:

    awk '{print $1}' FS=/ RS='\n' file1 FS='\n' RS= file2
    

    Onde você pode especificar um FS/ RSpor arquivo diferente. Também é comumente usado em:

    awk '!file1_processed{a[$0]; next}; {...}' file1 file1_processed=1 file2
    

    Qual é uma versão mais segura de:

    awk 'NR==FNR{a[$0]; next}; {...}' file1 file2
    

    (que não funciona se file1estiver vazio)

    Mas isso atrapalha quando você tem arquivos cujo nome contém =caracteres.

    Agora, isso é apenas um problema quando o que resta do primeiro é um nome de variável =válido .awk

    O que constitui um nome de variável válido em awké mais estrito do que em sh.

    POSIX requer que seja algo como:

    [_a-zA-Z][_a-zA-Z0-9]*
    

    Com apenas caracteres do conjunto de caracteres portátil. No entanto, o /usr/xpg4/bin/awkSolaris 11, pelo menos, não é compatível a esse respeito e permite quaisquer caracteres alfabéticos na localidade em nomes de variáveis, não apenas a-zA-Z.

    Portanto, um argumento como x+y=fooou =barou ./foo=barainda é tratado como um nome de arquivo de entrada e não como uma atribuição, pois o que resta do primeiro =não é um nome de variável válido. Um argumento como Stéphane=Chazelas.txtpode ou não, dependendo da awkimplementação e localidade.

    É por isso que com awk, é recomendado usar:

    awk '...' ./*.txt
    

    ao invés de

    awk '...' *.txt
    

    por exemplo, para evitar o problema se você não puder garantir que o nome dos txtarquivos não contenha =caracteres.

    Além disso, esteja ciente de que um argumento como -vfoo=bar.txtpode ser tratado como uma opção se você usar:

    awk -f file.awk -vfoo=bar.txt
    

    (também se aplica às awk '{code}' -vfoo=bar.txtversões awkdo busybox anteriores a 1.28.0, veja o relatório de bug correspondente ).

    Novamente, o uso ./*.txtcontorna isso (usar um ./prefixo também ajuda com um arquivo chamado -que, de outra forma awk, entende como entrada padrão ).

    Por isso também

    #! /usr/bin/awk -f
    

    shebangs realmente não funcionam. Enquanto var=valueaqueles podem ser contornados fixando os ARGVvalores (adicione um ./prefixo) em uma BEGINdeclaração:

    #! /usr/bin/awk -f
    BEGIN {
      for (i = 1; i < ARGC; i++)
        if (ARGV[i] ~ /^[_[:alpha:]][_[:alnum:]]*=/)
          ARGV[i] = "./" ARGV[i]
    }
    # rest of awk script
    

    Isso não ajudará com as opções, pois essas são vistas awke não o awkscript.

    Um possível problema cosmético com o uso desse ./prefixo é que ele acaba em FILENAME, mas você sempre pode usá substr(FILENAME, 3)-lo para removê-lo se não quiser.

    A implementação do GNU awkcorrige todos esses problemas com sua -Eopção.

    Depois -Ede , o gawk espera apenas o caminho do awkscript (onde -ainda significa stdin) e, em seguida, uma lista apenas de caminhos de arquivos de entrada (e lá, nem -é tratado especialmente).

    É especialmente projetado para:

    #! /usr/bin/gawk -E
    

    shebangs onde a lista de argumentos são sempre arquivos de entrada (observe que você ainda está livre para editar essa ARGVlista em uma BEGINinstrução).

    Você também pode usá-lo como:

    gawk -e '...awk code here...' -E /dev/null *.txt
    

    Usamos -Ecom um script vazio ( /dev/null) apenas para garantir que *.txtdepois sejam sempre tratados como arquivos de entrada, mesmo que contenham =caracteres.

    • 22
  3. Sergiy Kolodyazhnyy
    2018-12-23T14:11:40+08:002018-12-23T14:11:40+08:00

    Para citar a documentação do gawk (observe a ênfase adicionada):

    Quaisquer argumentos adicionais na linha de comando são normalmente tratados como arquivos de entrada a serem processados ​​na ordem especificada. No entanto, um argumento que tem o formato var=value, atribui o valor do valor à variável var — ele não especifica um arquivo.

    Por que o comando para e espera? Porque no formulário awk 'processing_script_here' my=file.txt não há arquivo especificado pela definição acima - my=file.txté interpretado como atribuição de variável e, se não houver arquivo definido awk, lerá stdin (também evidente straceque mostra que awk em tal comando está aguardando read(0,'...)syscall.

    Isso também está documentado nas especificações POSIX awk , veja a seção OPERANDS e parte das atribuições )

    A atribuição de variável é evidente em awk '{print foo}' foo=bar /etc/passwdque o valor de fooé impresso para cada linha em /etc/passwd. Especificar ./foo=barou caminho completo, no entanto, funciona.

    Observe que stracea execução awk '1' foo=bar, bem como a verificação com cat foo=bar, mostra que esse é um problema específico do awk, e o execve mostra o nome do arquivo como argumento passado, portanto, os shells não têm nada a ver com as atribuições de variáveis ​​​​env neste caso.

    Além disso, observe que awk '...script...' foo=barisso não causará a criação de variáveis ​​de ambiente pelo shell, pois as atribuições de variáveis ​​de ambiente devem preceder um comando para entrar em vigor. Veja POSIX Shell Grammar Rules , ponto número 7. Além disso, isso pode ser verificado viaawk '{print ENVIRON["foo"]}' foo=bar /etc/passwd

    • 4

relate perguntas

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

  • anexar linhas após outros arquivos linha por linha

  • Como remover uma única linha entre duas linhas

  • Reorganize as letras e compare duas palavras

  • Embaralhamento de arquivo de várias linhas

Sidebar

Stats

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

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

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 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

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 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
    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
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +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
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +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