我正在尝试使用find
这样的命令
cut -f 4 file.txt | awk 'NR>1' | find ./ -name
在 awk 命令之后我的输入如下所示
foo.c
foo.txt
abc.txt
如何将来自上一个命令的文件名提供给 find 命令?
所以基本上是寻找foo.c
并获取它的路径,然后foo.txt
获取它的路径等等。
答案1
在这里,可以更轻松地find
找到每个文件并awk
选择具有所需名称的文件。例如,假设 aawk
支持将记录分隔符设置为 NUL:
find . -print0 | awk '
! names_loaded {if (NR>1) names[$4]; next}
$NF in names' FS='\t' file.txt names_loaded=1 FS=/ RS='\0' -
答案2
您必须为每个单独添加一堆选项-name
。尝试这个:
IFS='
'
set -o noglob
find . -false $(awk -F '\t' -v OFS='\n' '
NR>1 && $4 != "" { print "-o", "-name", $4}' file.txt)
awk
每行打印一个参数,我们$(...)
在 shell 中使用 split+glob 运算符(不带引号),其中全局部分禁用和分裂部分调整为在换行符上拆分,仅将它们作为参数传递给find
.
file.txt
如果很大,这可能会失败。还要注意名称被视为模式。例如,如果有一行包含[f]ile*
,它将查找名称以 开头的所有文件file
,而不是名为 的文件[f]ile*
。
正常的和安全安排将使用xargs
:
something something | xargs -r0 find . -false
但xargs
可以运行find
多次并在 an-o
和 a之间-name
或在-name
和实际文件名之间分割参数列表。我们可以通过传递-n 150
或 3 的倍数的任何数字来避免这种情况,并且希望该数字足够小以适应参数大小的限制。
首先放置-false
简化了其余的处理,因为这样,我们可以使输出完全规则,在-o
每个之前都有一个-name
。
如果您find
不支持该非标准谓词,您可以将其替换为-links 0
或 任何保证为假的内容。
答案3
您可以在这里使用zsh
递归 glob,而不是find
让它变得更容易:
filenames=( ${(f)"$(<file.txt tail -n +2 | cut -f 4)"} )
print -rC1 -- **/(${(~j[|])filenames})(ND)
如果我们使用f
参数扩展标志cut
分割on lineeed的输出f
,并使用交替 glob 运算符~j[|]
连接数组成员,对于任意数量的子目录,对于 dotglob,对于 nullglob。|
**/
D
N
匹配项在列上print
显示。r
1
C
如果名称被解释为模式而不是文件名,您可以将其更改为:
print -rC1 -- **/(${(j[|])~filenames})(ND)
这里~
的 globsubst 适用于整个扩展,而不仅仅是oin 标志|
引入的扩展j
。
答案4
我会将find
其整个输出发送到awk
,并使用哈希表搜索所需的名称。基本上,就像:
Awk='
#.. Extract required names from list.
FS == " " { if (FNR > 1) Name[$4]; next; }
#.. List paths for given names.
$(NF) in Name { print; }
'
find . -type f -print0 | awk "${Awk}" FS=' ' "file.txt" RS=$'\0' FS='/' - | sort
排序按名称收集输出(目录树中可能有重复项)。
一种改进可能是计算Name[]
数组中的命中数,并列出 END 块中没有命中的名称。
请注意,find
输出是以 null 结尾的(-print0
在 find 中,RS
如NUL
在 awk 中),并且仅引用文件(目录意外匹配提供的名称是其他解决方案的问题)。