仅通过特定路径获取唯一的文件名

时间:2018-10-07 22:19:26

标签: linux bash

我有一个命令,可以计算以2010开头的所有文件名

find folder_name/ -path '*/*/*/*/2010*'

这很好,我得到了有效的结果。但是,举例来说,我具有以下文件结构:

*/atl/apple/banana/20101004
*/atl/apple/oranges/20101004

这些都属于同一类别,因为它们都属于atl。因此,不是计数为2,而是应该为1。有没有办法使我仅获得每个城市名称(atl)的唯一值?

注意:末尾的日期是文件名。没有文件扩展名。

编辑 假设我有这个命令

find example/ -path '*/*/*/*/2010*'

我得到这些作为结果:

example/atl/apples/bananas/20100510 //1 instance of this date in atl
example/atl/apples/oranges/20100510 //This date is a duplicate and should not be counted
example/nyc/apples/bananas/20100510 //1 instance of this date in nyc
example/nyc/apples/bananas/20100511 //1 instance of this date in nyc
example/bkg/apples/bananas/20100510 //1 instance of this date in bkg

在此示例中,计数应为4。atl中的20100510显示多次,因此应仅计数一次。

4 个答案:

答案 0 :(得分:0)

使用sort显示唯一的城市/日期对,加上wc对其进行计数,并使用bash 处理替代使其看起来更好:

find folder_name/ -path '*/*/*/*/2010*' | 
sort -t '/' -k 2,2 -k 5,5 -u | tee >(echo "Count: $(wc -l)")

输出(根据“结果” 示例数据):

example/atl/apples/bananas/20100510
example/bkg/apples/bananas/20100510
example/nyc/apples/bananas/20100510
example/nyc/apples/bananas/20100511
Count: 4

或者仅打印城市/日期对,请在cut之前添加tee

find folder_name/ -path '*/*/*/*/2010*' | 
sort -t '/' -k 2,2 -k 5,5 -u | cut -d '/' -f 2,5 | tee >(echo "Count: $(wc -l)")

输出:

atl/20100510
bkg/20100510
nyc/20100510
nyc/20100511
Count: 4

工作原理:

  1. find一些文件,深五个级别。
  2. 告诉sort按第二和第五字段排序,仅打印唯一的城市/日期行。请注意,需要两个 -k开关;仅使用-k 2,5不会以相同的方式工作。
  3. wc计算行数。

答案 1 :(得分:0)

如果使用awk仅选择城市名称和文件名等字段,则可以通过管道传输到sort -u,然后通过wc进行计数。这将对来自同一城市的所有结果产生一次计数。像这样:

find folder_name/ -path '*/*/*/*/2010*' |
    awk -F/ '{ print $2, $5 }' |
    sort |
    uniq -c

答案 2 :(得分:0)

使用find本身(而不是依赖外部工具)来进行除mkdir -p example/{atl,nyc,bkg}/apples/{bananas,oranges} touch \ example/atl/apples/bananas/20100510 \ example/atl/apples/oranges/20100510 \ example/nyc/apples/bananas/20100510 \ example/nyc/apples/bananas/20100511 \ example/bkg/apples/bananas/20100510 本身之外的所有操作可能看起来如下所示。


给出问题中描述的设置:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: Bash 4.0 needed" >&2; exit 1;; esac

declare -A seen=( )

while IFS= read -r -d '' name; do
  name=${name#example/}  # ignore the leading example/
  first_piece=${name%%/*}
  last_piece=${name##*/}
  seen[${first_piece}/${last_piece}]=1
done < <(find example -type f -print0)

echo "Number of distinct first/last pairs: ${#seen[@]}"
echo "Those individual pairs are:"
printf ' - %s\n' "${!seen[@]}"

...实现:

Number of distinct first/last pairs: 4
Those individual pairs are:
 - atl/20100510
 - bkg/20100510
 - nyc/20100510
 - nyc/20100511

...正确发出作为输出:

git commit -am "message" --author="Linus Torvalds <torvalds@linux-foundation.org>"

答案 3 :(得分:0)

通过@charles的启发,我创建了以下结构:

mkdir -p example/{atl,nyc,bkg}/apples/{bananas,oranges}
touch \
example/atl/apples/bananas/20100510 \
example/atl/apples/oranges/20100510 \
example/nyc/apples/bananas/20100510 \
example/nyc/apples/bananas/20100511 \
example/bkg/apples/bananas/20100510 \
example/bkg/coconuts/bananas/20100510

然后,假设您认为文件是重复的,因为它位于同一 level-2 子目录(苹果或椰子)中,我建议使用以下命令:

for i in $(find example -maxdepth 2 -mindepth 2 -type d); do find $i -path '*/*/*/*/2010*'|awk -F\/ '{print $NF}'|sort -u;done|wc -l

结果是:

5

如果由于文件位于相同的 level-1 子目录(atl,nyc或bkg)中,因此要考虑它是重复文件,请使用以下命令:

for i in $(find example -maxdepth 1 -mindepth 1 -type d); do find $i -path '*/*/*/*/2010*'|awk -F\/ '{print $NF}'|sort -u;done|wc -l

结果是:

4