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 - 已删除
我希望仅打印存在的文件,但此命令不起作用。
答案 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;
}
注意:
答案 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(…)
您也可以执行其他任务,只要输出是非负整数(假设它们在返回之前会 exit_code % 256
,只要您能轻松解释该输出。快速示例({{ 1}} 是单引号 \047
,'
是百分比 \045
,140 是重音符 [ ` ] )
%
正确打印出“16”来测量字符串的长度。
我完全意识到这是使用 system( ) 和 POSIX 退出代码的可怕方式。