Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

awk check file exists

Tags:

file

unix

awk

printf "2015-03-02|/home/user/.ssh/config\n2015-03-02|/home/user/Desktop/temp328\n" | awk -F\| 'if ( -f $2 )  { print $2}'

or

printf "2015-03-02|/home/user/.ssh/config\n2015-03-02|/home/user/Desktop/temp328\n" | awk -F\| '{if (system("test -f" $2)) print $2}'

/home/user/.ssh/config\n2015-03-02 - exists

/home/user/Desktop/temp328 - removed

I want print only exist files but this commands not working.

like image 339
pepco2 Avatar asked Mar 26 '15 16:03

pepco2


3 Answers

The second attempt was fairly close; you need a space after the test -f.

base$ echo '2015|/etc/mtab
> 2015|/etc/ntab' | awk -F\| '{ if (system("test -f " $2)) print $2}'
/etc/ntab

You probably want to invert to use if (system(...)==0) to get the semantics you expected. Also, somewhat more elegantly, Awk wants a condition outside the braces, so you can avoid the explicit if.

awk -F\| 'system("test -f " $2)==0 { print $2 }'

Agree with commenters that using Awk for this is borderline nuts.

If, as indicated in comments, you need to work with completely arbitrary file names, you can add code to quote any shell specials:

awk -F\| 'system ("test -f " gensub(/[^\/A-Za-z0-9]/, "\\\\&", "g", $2))==0 {
   print $2 }'   # caveat: gensub() is gawk only

... but your overall solution does not cope with file names containing a newline character or a pipe character (since you are using those as record and field separators, respectively) so again, abandoning Awk and starting over with a different approach may be the sane way forward.

(The character class in the substitution is incomplete; there are various punctuation characters etc which could be added, and I may be missing something significant; but on quick examination, the superfluous backslashes should be harmless. If you don't have Gawk, see here and/or, again, consider abandoning this approach.)

while IFS='|' read -r stuff filename; do
    test -f "$filename" && echo "$filename"
done <<':'
2015|/etc/mtab
2016|/etc/ntab
2017|/path/to/file with whitespace in name
2018|/path/to/file\with[funny"characters*in(file'name|even pipes, you see?
:

(Still no way to have a newline, but everything else should be fine.)

like image 98
tripleee Avatar answered Oct 26 '22 23:10

tripleee


With GNU awk you can use stat() included with the filefuncs extension:

$ ls -l 
-rw-r--r-- 1 james james 4 Oct  3 12:48 foo
-rw------- 1 root  root  0 Oct  3 12:48 bar

Awk:

$ awk -v file=foo '
@load "filefuncs"
BEGIN {
    ret=stat(file,fdata)
    printf "ret:  %d\nsize: %d\n",ret,fdata["size"]
}'

Output for -v file= foo:

ret:  0
size: 4

for bar:

ret:  0
size: 0

and for nonexistent baz:

ret:  -1
size: 0
like image 33
James Brown Avatar answered Oct 26 '22 22:10

James Brown


It's easy to check for the existence of a readable file in awk, without having to resort to spawning something with system(). Just try to read from the file.

From awk's man page (on my system anyway):

In all cases, getline returns 1 for a successful input, 0 for end of file, and -1 for an error.

So. Some example code.

#!/usr/bin/awk -f

function file_exists(file) {
  n=(getline _ < file);
  if (n > 0) {
    print "Found: " file;
    return 1;
  } else if (n == 0) {
    print "Empty: " file;
    return 1;
  } else {
    print "Error: " file;
    return 0;
  }
}

BEGIN {

  file_exists(ARGV[1]);

}

Gives me these results:

$ touch /tmp/empty
$ touch /tmp/noperm ; chmod 000 /tmp/noperm
$ ./check.awk /etc/passwd
Found: /etc/passwd
$ ./check.awk /nonexistent
Error: /nonexistent
$ ./check.awk /tmp/empty
Empty: /tmp/empty
$ ./check.awk /tmp/noperm
Error: /tmp/noperm

Using your sample data:

$ fmt="2015-03-02|/home/user/.ssh/config\n2015-03-02|/home/user/Desktop/temp328\n"
$ printf "$fmt" | cut -d\| -f2 | xargs -n 1 ./check.awk
Error: /home/user/.ssh/config
Error: /home/user/Desktop/temp328

For more general use, you could shorten this function to something like:

function file_exists(file) {
  if ((getline _ < file) >= 0) { return 1; }
}
like image 37
ghoti Avatar answered Oct 27 '22 00:10

ghoti