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 / 769898
Accepted
Olivier Dulac
Olivier Dulac
Asked: 2024-02-23 00:14:17 +0800 CST2024-02-23 00:14:17 +0800 CST 2024-02-23 00:14:17 +0800 CST

awk (e gawk): como evitar erros fatais quando 1 dos N arquivos de entrada está ilegível

  • 772

caso de teste: (com um usuário não root, pois o root desconsideraria a permissão 000...)

#in a clean directory:
[ -f file_1 ] && chmod 600 file_? # for repeat tests...
for i in file_1 file_2 file_3; do
    printf 'A\nB\n' > "$i" 
    # we need at least 1 char : awk/gawk silently skips empty files...
done
chmod 000 file_2
awk '(FNR==1) { print FILENAME }' file_? 
  # tried with : regular (old unixes) awk on AIX. and gawk on Linux.
  # the fatal "permission denied" on file_2 stops [g]awk.

Existe uma maneira de detectar esse erro fatal e continuar com os próximos arquivos?

(caso contrário, acho bastante preocupante: usar o awk em vários arquivos não garante o processamento de todos eles, pois ele será encerrado fatalmente se algum deles estiver ilegível)

Por favor, se possível: responda

  • para awk normal,
  • e para ficar de boca aberta
  • e quaisquer outras versões relevantes do awk? (não é? etc)
awk
  • 2 2 respostas
  • 380 Views

2 respostas

  • Voted
  1. Stephen Kitt
    2024-02-23T00:29:49+08:002024-02-23T00:29:49+08:00

    Com GAWK:

    gawk 'BEGINFILE { if (ERRNO) nextfile } (FNR==1) { print FILENAME }' file_?
    

    No BEGINFILEbloco, ERRNOfica vazio se o arquivo foi aberto com sucesso e nextfilepode ser usado para pular para o próximo e evitar o resgate com erro.

    Não acho que isso seja compatível com outras implementações do AWK.

    Portavelmente, você pode iterar todos os argumentos, verificar se eles apontam para um arquivo ilegível e, em caso afirmativo, removê-los dos argumentos antes que o AWK comece a processá-los; o manual GAWK tem um exemplo de implementação . No entanto, isso é atrevido, pois um arquivo verificado usando esse loop pode se tornar ilegível (ou vice-versa) antes que o AWK comece a processá-lo.

    • 9
  2. Best Answer
    Ed Morton
    2024-02-23T06:27:59+08:002024-02-23T06:27:59+08:00

    Como @StephenKitt e @ilkkachu já apontaram, o manual do gawk contém algum código que removerá arquivos ilegíveis da ARGV[]seção BEGIN, mas que tem uma condição de corrida entre o momento em que o arquivo é testado e quando o awk realmente tenta ler seu conteúdo, o que pode ser muito mais tarde se os arquivos anteriores forem grandes.

    Eu usaria o script na resposta de @StephenKitt se você tiver o gawk ou o script no manual do gawk, caso contrário, a menos que você ache que pode ter esse problema de condição de corrida, pois o script do manual do gawk é mais claro, mais breve, mais simples, mais eficiente, etc. do que o que está abaixo e não requer um arquivo temporário e variáveis ​​globais, mas para aqueles que estão preocupados com essa condição de corrida - aqui está um script mais complicado que funcionará em qualquer awk e depende da criação de um arquivo temporário para abrir imediatamente antes de tentar para abrir qualquer arquivo real e nesse ponto testar se o próximo arquivo real é legível ou não.

    $ cat skip.awk
    function addTmp(        cmd, oArgv, i, j) {
        cmd = "mktemp"
        cmd | getline TmpChkFile
        close(cmd)
    
        if ( TmpChkFile != "" ) {
            print "" > TmpChkFile
            close(TmpChkFile)
    
            for (i in ARGV) {
                oArgv[i] = ARGV[i]
            }
            oArgc = ARGC
    
            ARGC = 1
            for (i = 1; i < oArgc; i++) {
                if ( ! (oArgv[i] ~ /^[a-zA-Z_][a-zA-Z0-9_]*=.*/ \
                        || oArgv[i] == "-" || oArgv[i] == "/dev/stdin") ) {
                    # not assignment or standard input so a file name
                    ARGV[ARGC] = TmpChkFile
                    ArgFileNames[++j] = oArgv[i]
                    ArgFileIndices[j] = ++ARGC
                }
                ARGV[ARGC++] = oArgv[i]
            }
        }
    }
    
    function rmvTmp() {
        system("rm -f \047" TmpChkFile "\047")
    }
    
    function chkTmp(        stderr, line) {
        if ( (FNR == 1) && (FILENAME == TmpChkFile) ) {
            ++TmpFileNr
            if ( (getline line < ArgFileNames[TmpFileNr]) < 0 ) {
                stderr = "cat>&2"
                printf "Warning: skipping unreadable file \"%s\"\n", ArgFileNames[TmpFileNr] | stderr
                close(stderr)
                delete ARGV[ArgFileIndices[TmpFileNr]]
            }
            close(ArgFileNames[TmpFileNr])
            next
        }
    }
    
    BEGIN { addTmp() }
    END { rmvTmp() }
    { chkTmp() }
    

    Se o seu awk suportar múltiplos -fargumentos (por exemplo, conforme exigido pelo POSIX ) ou qualquer outra forma de executar vários scripts de uma vez (por exemplo, GNU awk has @include), então você pode usar esse método para incluir o acima junto com o seu script real (caso contrário, copie/cole o acima no mesmo arquivo), por exemplo, se você tiver um script como:

    $ cat tst.awk
    FNR == 1 { print FILENAME, $0 }
    

    e arquivos como:

    $ ls file_{1..3}
    ls: cannot access 'file_2': No such file or directory
    file_1  file_3
    

    então, com qualquer awk POSIX (e a maioria, senão todos, outros) você pode fazer:

    $ awk -f skip.awk -f tst.awk file_{1..3}
    file_1 A
    Warning: skipping unreadable file "file_2"
    file_3 C
    

    A maior parte do trabalho acima é feito BEGINchamando uma vez antes do primeiro arquivo de entrada ser aberto para garantir que um arquivo temporário legível exista ARGV[]imediatamente antes de cada arquivo de entrada real, então chkTmp()é chamado para cada linha de entrada, mas só faz algo quando é o primeiro (e única) linha do arquivo temporário e essa coisa é tentar abrir o arquivo de entrada real que vem depois dele em ARGV[]. Depois ENDé só remover o arquivo temporário. Portanto, a sobrecarga extra real é a chamada chkTmp()e o teste FNR==1para cada linha de entrada.

    Estou criando um arquivo temporário em vez de usar um arquivo existente porque não há nenhum arquivo com existência garantida em todas as caixas Unix e, mesmo se houvesse, teria que ter exatamente 1 linha para evitar adicionar sobrecarga extra de chkTmp()ter que ler todas as linhas desse arquivo, já que nem todos os awks suportam nextfile(ou poderíamos chamar isso em vez de nextinside chkTmp()).

    • 3

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

    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