awk检查文件存在

时间:2015-03-26 16:57:54

标签: 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}'

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 - 存在

/ home / user / Desktop / temp328 - 已删除

我希望仅打印存在的文件,但此命令不起作用。

7 个答案:

答案 0 :(得分:4)

第二次尝试相当接近;你需要test -f之后的空格。

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

您可能希望反转使用if (system(...)==0)来获取您期望的语义。而且,更优雅的是,Awk想要在大括号之外的条件,所以你可以避免使用明确的if

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

与使用Awk的评论者达成协议,这是一个临界坚果。

如果如评论中所示,您需要使用完全任意的文件名,则可以添加代码以引用任何shell特殊内容:

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

...但是你的整体解决方案不能处理包含换行符或管道符的文件名(因为你分别使用它们作为记录和字段分隔符)所以再次放弃Awk并重新开始使用不同的方法可能是理智的前进方式。

(替换中的字符类是不完整的;有各种标点字符等可以添加,我可能会遗漏一些重要的东西;但是在快速检查时,多余的反斜杠应该是无害的。如果你没有'有Gawk,请参阅here和/或再次考虑放弃这种方法。)

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?
:

(仍然无法使用换行符,但其他一切都应该没问题。)

答案 1 :(得分:0)

很容易检查awk中是否存在可读文件,而不必使用system()生成某些内容。只是尝试从文件中读取。

从awk的手册页(无论如何在我的系统上):

  

在所有情况下,getline都会返回1表示成功         输入,0表示文件结尾,-1表示错误。

因此。一些示例代码。

#!/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]);

}

给我这些结果:

$ 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

使用您的样本数据:

$ 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

对于更一般的用途,您可以将此功能缩短为:

function file_exists(file) {
  if ((getline _ < file) >= 0) { return 1; }
}

答案 2 :(得分:0)

通过GNU awk,您可以使用stat()扩展中包含的filefuncs

$ 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 -v file=foo '
@load "filefuncs"
BEGIN {
    ret=stat(file,fdata)
    printf "ret:  %d\nsize: %d\n",ret,fdata["size"]
}'

-v file= foo的输出:

ret:  0
size: 4

bar

ret:  0
size: 0

,对于不存在的baz

ret:  -1
size: 0

答案 3 :(得分:0)

不是我真正的答案,但是这里还没有记录。来自“ The GNU Awk User's Guide”:

提供此方法:

  # readable.awk --- library file to skip over unreadable files

  BEGIN {
      for (i = 1; i < ARGC; i++) {
          if (ARGV[i] ~ /^[[:alpha:]_][[:alnum:]_]*=.*/ \
              || ARGV[i] == "-" || ARGV[i] == "/dev/stdin")
              continue    # assignment or standard input
          else if ((getline junk < ARGV[i]) < 0) # unreadable
              delete ARGV[i]
          else
              close(ARGV[i])
      }
  }

实际的代码段正在处理命令行。这个问题的有用处是else if ...

   else if ((getline junk < ARGV[i]) < 0) # unreadable
        delete ARGV[i]
      :

这基本上是readline中命名的文件上的ARGV[i],如果失败,则删除数组元素。文件不存在或不可读。

无论哪种方式,您都无法使用它。全部都在相同的aWk进程中,shell没有执行程序,等等。

我今天需要这个,我编写了以下小函数:

  ##  file_exist
  #     * ref: [12.3.3 Checking for Readable Data Files](http://langevin.univ-tln.fr/cours/COMPIL/tps/awk.html#File-Checking)
  #         o [The GNU Awk User's Guide](http://langevin.univ-tln.fr/cours/COMPIL/tps/awk.html)
  #

  function file_exist(  file_path, _rslt, _junk  )
  {
      _rslt = (0==1);     #   false

      if( (getline _junk < file_path) > 0)  )    ## readable 
      {
          _rslt = (1==1);
          close( file_path );
      }
      return _rslt;
  }

注意:

  • 文件为空时,函数返回TRUE

答案 4 :(得分:0)

您可以使用 BASH 轻松完成此操作,并将结果通过管道传送到 AWK。

% ls
file_list file1 file3
% cat file_list
file1
file2
file3
file4
% cat file_list | bash -c 'while read file ; do [ -f "$file" ] || echo "No file: $file"; done'
No file: file2
No file: file4

答案 5 :(得分:0)

#!/usr/bin/gawk -f
@load "filefuncs"
 function exist(file){
  return stat(file, null)
 }
BEGIN{
 print exist("/etc/passwsd")}

如果文件存在则返回'0',否则返回'-1'
'null' - 数组的任何自由名称(需要第二个参数!)
如果您不需要任何功能,瞧:

#!/usr/bin/gawk -f
@load "filefuncs"
BEGIN{print stat("/etc/passwsd", null)}

答案 6 :(得分:0)

我正在从另一个线程重新粘贴我的答案,因为它在检查文件方面似乎是相对的。我主要是添加关于如何利用 system() 来做奇怪的事情的通用案例

事实上,在某些情况下,您确实可以利用system()直接获得您想要的输出,而无需处理格式化命令,通过 getline 运行它,临时存储它,重置 RS(如果您之前已将其设置为“^$”),并在返回输出之前关闭该命令,例如:

-rw-r--r--  1 501  20  77079 Jul 26 13:07 ./selectWoo.full.min.js.txt

valid file :: exist_and_non_empty

non-existent file :: cannot locate

32297  gprintf '\033c\033[3J'; echo; ls -lFGnd "./selectWoo.full.min.js"*; 
       mawk2 'function filetest(fn) { 
          gsub(/\047/,"&\134\047&",fn); # in case single-qt in filename
          return 
              system(" exit \140 [ -r \047"(fn)"\047 ] \140 ") 
              ? "cannot locate" 
              : "exist_and_non_empty" 
       } BEGIN { 
           ORS = "\n\n"; 
           fn_pfx="./selectWoo.full.min.js";
           print "\nvalid file :: "      filetest(fn_pfx ".txt"); 
           print "non-existent file :: " filetest(fn_pfx ".txt_fake") 
      }' ; 
      history 1 ; echo

我只是为了说明目的而在此处进行更详细的说明。我们没有返回 system() 调用是否成功,而是直接将退出代码设置为文件测试的退出代码。

如果你想把返回值简化为布尔值,那就让它

<块引用>

return ! system(…)

  • 我还没有测试过所有的 POSIX 文件/目录信息检查标志,但我无法想象有多少可能会导致此代码失败。

您也可以执行其他任务,只要输出是非负整数(假设它们在返回之前会 exit_code % 256,只要您能轻松解释该输出。快速示例({{ 1}} 是单引号 \047' 是百分比 \045,140 是重音符 [ ` ] )

%

正确打印出“16”来测量字符串的长度。

我完全意识到这是使用 system( ) 和 POSIX 退出代码的可怕方式。