Jen*_*fer 4 shell shell-script filenames
我有一个场景,我循环遍历给定路径中的所有目录和子目录;如果找到具有特定扩展名 (.txt) 的文件,则将目录和子目录的名称存储在数组中。后来,我在这些目录上读取并执行命令。
这是我正在执行的操作:
!/bin/bash
x=( $(find . -name "*.txt") ); echo "${x[@]}"
for item in "${x[@]}"; { echo "$item"; }
Run Code Online (Sandbox Code Playgroud)
我当前的输出是:
./dir1/file1.txt
./dir1/file2.txt
./dir2/subdir1/subdir2/file3.txt
Run Code Online (Sandbox Code Playgroud)
但我想要实现的是,x即使目录包含多个.txt文件,数组中也不应该有任何重复项。此外,我不想将文件名存储为路径;该数组应仅包含目录名称。
预期输出:
./dir1
./dir2/subdir1/subdir2/
Run Code Online (Sandbox Code Playgroud)
使用bash:
shopt -s globstar
shopt -s dotglob nullglob
dirs=( ./**/*.txt ) # glob the names
dirs=( "${dirs[@]%/*}" ) # remove the filenames at the end
Run Code Online (Sandbox Code Playgroud)
这为您提供了可能有重复项的目录路径数组。要删除重复项,请使用关联数组:
declare -A seen
for dirpath in "${dirs[@]}"; do
seen["$dirpath"]=''
done
dirs=( "${!seen[@]}" ) # extract the keys from the "seen" hash
Run Code Online (Sandbox Code Playgroud)
然后,要打印它们,
printf '%s\n' "${dirs[@]}"
Run Code Online (Sandbox Code Playgroud)
在zshshell 中,您可以类似地执行此操作,但使用唯一的数组和 shell 的奇特的全局限定符来删除路径末尾的文件名:
typeset -U dirs
dirs=( ./**/*.txt(DN:h) )
Run Code Online (Sandbox Code Playgroud)
模式后面的通配限定符中的D和充当和中的作用,即,它们启用隐藏名称的匹配,并在根本没有匹配的情况下删除该模式。最后一个给出了生成的路径名的“头”,即末尾没有文件名的目录路径。Ndotglobnullglobbash:h
shellzsh不必**显式启用使用,因为您必须bash设置globstarshell 选项。
然后,要打印它们,
print -r -C1 -- $dirs
Run Code Online (Sandbox Code Playgroud)
还相关: