在 fs 上我有这样的文件:
PREFIX_GROUPNAME_OTHERNAMES[.txt|.*]
例如:
A_ABC_A.txt
A_ABC_B.txt
A_ABC_C.txt
A_XYZ_A.txt
A_XYZ_B.txt
A_XYZ_C.txt
对于一些进一步的任务,我想获取组名称。
$# command i'm looking for
result:
> ABC XYZ
我知道名称结构而不是组名称。
想法(但似乎非常昂贵!(在大型列表中):
- 扫描所有文件
- 拆分名称,按组名称创建列表
- 返回组
find 和 awk 也许 tr 似乎是我在寻找解决方案时所寻找的
编辑:
这给出了一个不唯一的列表:
find ./ -iname '*.txt' | xargs -n 1 | cut -d '_' -f 2
> ABC
> ABC
> ABC
> XYZ
> XYZ
> XYZ
答案1
下面将仅使用shell字符串操作和标准工具sort
,以避免解析输出ls
或者find
,强烈建议不要这样做:
for f in *.*; do gr=${f#*_};gr=${gr%_*}; printf "%s\n" "$gr"; done | sort -u
在你的情况下,它应该准确输出
ABC
XYZ
解释:
- 我们迭代所有匹配的文件名
*.*
(应该是“最小综合”模式来捕获您所说的所有文件名) - 通过 shell 字符串操作,我们首先删除第一个之前的所有内容
_
,然后在第二步中删除从最后一个开始的所有内容_
。 - 我们通过以下方式输出结果
printf
(正如 Stéphane Chazelas 所指出的,您的 shell 不太可能缺少该命令)
最终的输出还不是唯一的。为了删除重复项,我们通过管道输出sort -u
。
笔记如果 - 正如您所说 - 您有很多与此模式匹配的文件,则您的for
循环参数列表可能会超出 shell 的内部限制。此外,虽然此方法避免了与文件名中的特殊字符相关的许多陷阱,但使用printf
和sort
意味着如果文件名包含换行符(这是许多文件系统上文件名的有效字符),该方法将会失败。
答案2
和zsh
:
typeset -U groups=( **/*_*_*.*(Ne['REPLY=${${(s[_])REPLY:t}[2]}']) )
typeset -U groups=(...)
:定义为具有唯一成员的groups
数组U
**/*_*_*.*
: 文件名在最右边、当前工作目录或下面至少有一个.
和至少两个s_
.
(Ne['code'])
: glob 限定符进一步限定 globN
:N
ullglob: 如果没有匹配则展开为空e['code']
变换每个 glob 扩展1(在$REPLY
中code
)$REPLY:t
:t
文件的 ail(基本名称)。${(s[_])var}
: 分裂_
(然后我们用 进行第二个[2]
)。
使用bash
(GNU shell)、GNUfind
和 GNU awk
,您可以执行类似的操作:
readarray -td '' groups < <(
LC_ALL=C find . -name '.?*' -prune -o \
-name '*_*_*.*' -printf '%f\0' |
gawk -v RS='\0' -v ORS='\0' -F _ '!seen[$2]++ {print $2}'
)
这些没有假设在前两个字符之间可以找到什么字符或非字符_
。
两者都会跳过隐藏文件和隐藏目录中的文件。要包含它们,请添加D
glob 限定符 inzsh
或删除-name '.?*' -prune -o
in find
。
如果有一个很大的文件列表,find
基于 - 的文件将更加内存友好,因为它不会将整个列表存储在内存中。您可以采用类似的方法zsh
:
typeset -A seen=()
: **/*_*_*.*(Ne['! seen[${${(s[_])REPLY:t}[2]}]='])
groups=( ${(k)seen} )
¹ 该代码的退出状态也决定了该文件是否被选择,但这里代码始终返回 true
答案3
在得到答案的同时我也找到了一个解决方案。正如@AdminBee 也提到的:
find
在来自文件系统的巨大结果列表中,xargs
如果您不能限制搜索模式(例如:“*.txt”),您可能会选择使用。
for f in ./some/path/*.txt; do gr=${f#*_};gr=${gr%_*}; echo "$gr"; done | sort -u
> ABC
> XYZ
find ./ -iname '*.txt' | xargs -n 1 | cut -d '_' -f 2 | sort -u
> ABC
> XYZ