在linux中使用find命令查找从上一个命令生成的文件名

在linux中使用find命令查找从上一个命令生成的文件名

我正在尝试使用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。|**/DN

匹配项在列上print显示。r1 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 中,RSNUL在 awk 中),并且仅引用文件(目录意外匹配提供的名称是其他解决方案的问题)。

相关内容