2015-12-01 16 views
6

Dire che ho la seguente struttura di file e directory:Come saltare una directory in awk?

$ tree 
. 
├── a 
├── b 
└── dir 
    └── c 

1 directory, 3 files 

Cioè, due file a e b insieme ad un dir dir, dove un altro file c stand.

voglio elaborare tutti i file con awk (GNU Awk 4.1.1, appunto), così faccio qualcosa di simile:

$ gawk '{print FILENAME; nextfile}' * */* 
a 
b 
awk: cmd. line:1: warning: command line argument `dir' is a directory: skipped 
dir/c 

Tutto è bene, ma il * si espande anche alla directory dir e awk tenta di elaborare esso.

Quindi mi chiedo: c'è un modo nativo awk possibile controllare se l'elemento dato è un file o meno e, in caso affermativo, saltarlo? Cioè, senza usare system() per questo.

mi ha reso il lavoro chiamando l'esterno system in BEGINFILE:

$ gawk 'BEGINFILE{print FILENAME; if (system(" [ ! -d " FILENAME " ]")) {print FILENAME, "is a dir, skipping"; nextfile}} ENDFILE{print FILENAME, FNR}' * */* 
a 
a 10 
a.wk 
a.wk 3 
b 
b 10 
dir 
dir is a dir, skipping 
dir/c 
dir/c 10 

nota anche il fatto che if (system(" [ ! -d " FILENAME " ]")) {print FILENAME, "is a dir, skipping"; nextfile} funziona contatore intuitivo: dovrebbe restituire 1 se vero, ma restituisce il codice di uscita.

ho letto in A.5 Extensions in gawk Not in POSIX awk:

E poi la pagina collegata dice:

4.11 Directories sul Riga di comando

In base allo standard POSIX, i file denominati nella riga di comando awk devono essere file di testo; è un errore fatale se non lo sono. La maggior parte delle versioni di awk trattano una directory sulla riga di comando come un errore fatale.

Per impostazione predefinita, gawk genera un avviso per una directory sul comando riga, ma in caso contrario lo ignora. Questo rende più facile da usare guscio jolly con il vostro programma awk:

$ gawk -f whizprog.awk *  Directories could kill this program 

Se uno dei --posix o --traditional opzioni è dato, quindi gawk ritorna a trattare una directory sulla riga di comando come errore fatale.

Vedere Extension Sample Readdir, per un modo di trattare le directory come dati utilizzabili da un programma awk.

E in effetti è il caso: lo stesso comando di prima con --posix fallisce:

$ gawk --posix 'BEGINFILE{print FILENAME; if (system(" [ ! -d " FILENAME " ]")) {print FILENAME, "is a dir, skipping"; nextfile}} ENDFILE{print FILENAME, NR}' * */* 
gawk: cmd. line:1: fatal: cannot open file `dir' for reading (Is a directory) 

ho controllato la sezione 16.7.6 Reading Directories che è legata sopra e si parla di readdir:

L'estensione readdir aggiunge un parser di input per le directory. L'utilizzo è il seguente:

@load "readdir"

Ma io non sono sicuro né come chiamare esso, né come usarla dalla riga di comando.

risposta

2

Se si voleva salvaguardare lo script da altre persone erroneamente che passano una directory (o qualsiasi altra cosa che non è un file di testo leggibile) ad esso, si potrebbe fare questo:

$ ls -F tmp 
bar dir/ foo 

$ cat tmp/foo 
line 1 

$ cat tmp/bar 
line 1 
line 2 

$ cat tmp/dir 
cat: tmp/dir: Is a directory 

$ cat tst.awk 
BEGIN { 
    for (i=1;i<ARGC;i++) { 
     if ((getline line < ARGV[i]) <= 0) { 
      print "Skipping:", ARGV[i], ERRNO 
      delete ARGV[i] 
     } 
     close(ARGV[i]) 
    } 
} 
{ print FILENAME, $0 } 

$ awk -f tst.awk tmp/* 
Skipping: tmp/dir Is a directory 
tmp/bar line 1 
tmp/bar line 2 
tmp/foo line 1 

$ awk --posix -f tst.awk tmp/* 
Skipping: tmp/dir 
tmp/bar line 1 
tmp/bar line 2 
tmp/foo line 1 

per POSIX getline rendimenti -1 se/quando non riesce cercando di recuperare un record da un file (ad esempio, file illeggibili o file non esiste o il file è una directory), è sufficiente GNU awk per dirti quale di quei fallimenti era per il valore di ERRNO se ti interessa.

+2

Niiiice! Quindi 'getline' su una directory non fallisce direttamente ma può essere gestito. – fedorqui

+0

RIght. Quando ho letto per la prima volta la tua domanda ho pensato che stavi cercando di usare awk per cercare file/dirs (mi dispiace - breve intervallo di attenzione!) Ma rileggendo sembra che tu voglia solo salvaguardare qualcuno che chiama lo script con un file non args: non c'è niente di sbagliato nel farlo e soprattutto è come lo si fa. Ho aggiornato la mia risposta per essere un po 'più favorevole a questo! –

+1

Sì, esattamente. Serve solo a prevenire avvertimenti, o persino codici di uscita, a causa del fatto che una dir viene espansa in una lista presumibilmente di solo file. Risposta molto interessante da cui ho imparato parecchio, grazie:) – fedorqui

4

Eviterei semplicemente di passare le directory a awk poiché anche POSIX dice che tutti gli argomenti di nome file devono essere file di testo.

È possibile utilizzare find per attraversare la directory:

find PATH -type f -exec awk 'program' {} + 
+0

Sì! Penso che questo sia il modo più pulito per farlo. Mi chiedo tuttavia se "awk" possa farlo in alcun modo. Ho modificato la mia domanda perché avevo erroneamente usato 'system()', quindi ora funziona così, ma ancora non mi piace il fatto di chiamare un comando esterno per questo. – fedorqui

+0

@fedorqui Ho anche giocato un po 'con '@load readdir' (bello sapere, grazie) .. Sono arrivato allo stesso risultato, cioè usando' system() 'per verificare se filename è una directory. Non vedo un modo diverso. – hek2mgl

+0

Grazie ancora hek! Alla fine ho accettato la risposta di Ed Morton poiché lo fa in modo awk. Anche se la raccomandazione non è di farlo in generale. – fedorqui