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)
Com GAWK:
No
BEGINFILE
bloco,ERRNO
fica vazio se o arquivo foi aberto com sucesso enextfile
pode 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.
Como @StephenKitt e @ilkkachu já apontaram, o manual do gawk contém algum código que removerá arquivos ilegíveis da
ARGV[]
seçãoBEGIN
, 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.
Se o seu awk suportar múltiplos
-f
argumentos (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:e arquivos como:
então, com qualquer awk POSIX (e a maioria, senão todos, outros) você pode fazer:
A maior parte do trabalho acima é feito
BEGIN
chamando uma vez antes do primeiro arquivo de entrada ser aberto para garantir que um arquivo temporário legível existaARGV[]
imediatamente antes de cada arquivo de entrada real, entãochkTmp()
é 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 emARGV[]
. DepoisEND
é só remover o arquivo temporário. Portanto, a sobrecarga extra real é a chamadachkTmp()
e o testeFNR==1
para 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 suportamnextfile
(ou poderíamos chamar isso em vez denext
insidechkTmp()
).