我正在尝试在HDFS中搜索镶木地板文件并将其列出。我正在使用它,效果很好。它查看了/sources.works_dbo
中的所有子目录,并为我提供了所有镶木地板文件:
hdfs dfs -ls -R /sources/works_dbo | grep ".*\.parquet$"
然而;我只想返回它遇到的每个子目录的第一个文件,这样每个子目录只出现在我的输出中的一行上。说我有这个:
sources/works_dbo/test1/file1.parquet
sources/works_dbo/test1/file2.parquet
sources/works_dbo/test2/file3.parquet
当我运行命令时,我希望输出看起来像这样:
sources/works_dbo/test1/file1.parquet
sources/works_dbo/test2/file3.parquet
答案 0 :(得分:2)
... | awk '!seen[gensub(/[^/]+$/,"",1)]++' file
sources/works_dbo/test1/file1.parquet
sources/works_dbo/test2/file3.parquet
以上使用GNU awk for gensub(),与其他awks一起使用变量和sub():
awk '{path=$0; sub(/[^/]+$/,"",path)} !seen[path]++'
它适用于任何长度路径的混合物。
答案 1 :(得分:1)
您可以使用sort -u
(唯一)和/
作为分隔符,并使用前三个字段作为键。 -s
选项(“stable”)确保保留的文件是每个子目录遇到的第一个文件。
对于此输入
sources/works_dbo/test1/file1.parquet
sources/works_dbo/test1/file2.parquet
sources/works_dbo/test2/file3.parquet
结果是
$ sort -s -t '/' -k 1,3 -u infile
sources/works_dbo/test1/file1.parquet
sources/works_dbo/test2/file3.parquet
答案 2 :(得分:1)
如果子目录的长度可变,则此awk
解决方案可能会派上用场:
hdfs dfs -ls -R /sources/works_dbo | awk '
BEGIN{FS="/"; OFS="/";}
{file=$NF; // file name is always the last field
$NF=""; folder=$0; // chomp off the last field to cache folder
if (!(folder in seen_dirs)) // cache the first file per folder
seen_dirs[folder]=file;
}
END{
for (f in seen_dirs) // after we've processed all rows, print our cache
print f,seen_dirs[f];
}'
答案 3 :(得分:1)
使用Perl:
hdfs dfs -ls -R /sources/works_dbo | grep '.*\.parquet$' | \
perl -MFile::Basename -nle 'print unless $h{ dirname($_) }++'
在上面的 perl 命令中:
-M
加载File::Basename
模块; -n
导致Perl为每个输入行应用通过-e
传递的表达式; -l
保留行终止符; $_
是保留当前读取行的默认变量; dirname($_)
返回$_
; $h
是一个哈希,其中键是目录名,值是整数0,1,2等; $h{ dirname($_) }
不为零。顺便说一句,您可以使用find
命令来代替hdfs dfs -ls -R
通过grep
传递结果:
hdfs dfs -find /sources/works_dbo -name '*.parquet'