我有一个包含 14 个目录的目录结构,其中包含一堆包含三列格式(用制表符分隔)数据的文件。我打算使用 find 和 awk 从每个文件中提取第二列,并使用相同的文件名但在不同的根文件夹下输出它。这是我的目录的草图。
data/all -> AA、AB、AC、AD ...(A* 为包含以 3 列格式存储数据的文件的文件夹,例如 AA100.txt、AA101.txt...)
我想要拥有同名的修改过的(单列)文件,但都在新的根目录 data/pos 下(而不是 data/all/)->AA、AB、AC、AD......(同样,每个都包含 A*100.txt、A*101......)
我尝试使用 find -exec 并给它 awk 命令,但是在将文件输出到正确的位置时遇到了问题。
当处于 data/all/
查找 * -type f -exec awk'{print$2}''{}'> ../pos/'{}'\;
但是在输出文件时,{} 作为输入文件的通配符似乎不起作用?
我做错了什么?(顺便说一下,我在 ubuntu 服务器上)
答案1
如果您想要的是所有文件,可以尝试不使用 find。在 中data/all/
,运行以下命令:
for file in ./*; do awk '{print$2}' "$file" > "../pos/$(basename $file)"; done
如果您想要覆盖下的整个层次结构中的文件/data/all
,您可以globstar
在使用 bash 时启用该选项(我相信这在 zsh 上“有效”),然后使用来**
匹配所有文件:
shopt -s globstar
for file in ./**; do awk '{print$2}' "$file" > "../pos/$(basename $file)"; done
答案2
我究竟做错了什么?
您使用重定向的方式> ../pos/'{}'
好像它是由find
或处理的awk
,但重定向是由 shell 处理的。 在您的例子中,这意味着您只能重定向整个的输出find
(而不是 的输出awk
)。
请注意,您通常不需要使用通配符作为*
的起始路径。这是您想要的find
常用方法吗?或者有什么理由吗?find .
find *
解决方案
find
与 Jacobo de Vera 的解决方案相比,我们将在这里保持灵活性。awk
在 shell 循环中运行:
find . -type f -print0 |
while read -r -d $'\0' x; do
awk '{print $2}' "$x" > "../pos/$(basename "$x")"
done
原始的方式-exec
效率较低,因为除了 之外,还会为每个文件启动一个 shell,awk
而且这里的多级转义相当复杂:
find . -type f -exec sh -c 'awk "{print \$2}" "{}" > "../pos/{}"' \;
也可能存在在内部进行重定向的替代解决方案awk
。
答案3
查找/路径 -exec ls -l {} \; | awk'{print$1}'