如何确保 3 个字符的文件名包含 2 个字符中的一个?

如何确保 3 个字符的文件名包含 2 个字符中的一个?

因此,我必须在目录中搜索长度为 3 个字符的文件。这很容易,问题是 3 个字符中至少有一个必须是“B”或“y”。我知道 [By] 可以确保字符是 B 或 ay,但是简单地执行 [By][By][By] 是不够的,因为并不要求所有 3 个字符都是 B 或 y;只要其中一个是就行。请帮忙。

答案1

您可以在 for 循环中进行模式匹配。

for file in ./???; do
    [[ -e $file && $file = *[By]* ]] || continue
    printf 'Do stuff with <%s>\n' "$file"
done

或者,您可以通过运行来启用扩展 glob shopt -s extglob。然后,您可以使用类似@([By]??|?[By]?|??[By])

shopt -s extglob
for file in ./@([By]??|?[By]?|??[By]); do
    [[ -e $file ]] || continue
    printf 'Do stuff with <%s>\n' "$file"
done

无论哪种方式都比涉及更有效率grep

如果您正在为 POSIX sh 编写脚本,您可以执行如下操作:

for file in ./???; do
    [ -e "$file" ] || continue
    case $file in 
        *[By]*) : ;;
        *) continue;;
    esac
    printf 'Do something with <%s>\n' "$file"    
done

最后,您可以使用三个 glob,尽管这会以不同的顺序迭代文件,并且您可能会冒着多次迭代同一个文件的风险。

for file in ./[By]?? ./?[By]? ./??[By]; do
    [ -e "$file" ] || continue
    printf 'Do something with <%s>\n' "$file"    
done

答案2

printf '%s\n' ??? | grep '[By]'

打印printf '%s\n'传递给它的每个参数,每行一个;是???一个 glob,它扩展为工作目录中每个三个字符的文件名。它通过管道传输到grep,它只打印包含您指定的模式的文件名。

顺便说一句,我发现自己用得printf '%s\n'太多了,~/.bashrc为了方便输入,我把下面的内容放进了我的:

alias necho='printf "%s\n"'  ##  newline-echo

大多数情况下,这都没问题:文件名包含换行符时会中断,但实际上这种情况非常罕见(我只在专门测试我的脚本时才见过)。使用以下方法可能可以快速实现一个简单的纯 bash 解决方案:外接球,但您也可以使用find来解决此问题:

find . -name '???' -a -name '*[By]*'

默认情况下,这将以递归方式执行;如果您不想这样,请使用-maxdepth 1

find . -maxdepth 1 -name '???' -a -name '*[By]*'

答案3

尝试以下命令:

cd /path/to/directory
ls | while read file; do if [ ${#file} -eq 3 ]; then echo $file; fi; done | grep '[By]'

或者:

for file in ???; do echo $file; done | grep '[By]'

或者,没有任何循环的变体:

ls | grep -ow '\w\{3\}' | grep '[By]'

ls将列出当前目录中的所有文件,然后我们只选择长度正好为 3 个字符的文件名,最后,使用grep,我们只选择包含B或 的文件名y

相关内容