shell 以编程方式为Find命令构建目录排除列表(Bash)

pieyvz9o  于 2023-05-07  发布在  Shell
关注(0)|答案(2)|浏览(187)

我有一个目录数组要从find命令的结果中排除,类似于EXCLUDE=("foo" "bar")
我可以从交互式终端运行它,如下所示:
find . -name 'hvr.yml' -not -path "foo/*" -not -path "bar/*"
所以我试着这样建立论点:

getServersToCheck() {

    # Build command arguments to exclude given dirs
    local exclude_command="-not -path"
    local excount=${#EXCLUDE[@]}
    for ((i=0;i<excount;i++)); do
        EXCLUDE[i]="${exclude_command} ${EXCLUDE[i]}/*"
    done

    find . -name 'hvr.yml' "${EXCLUDE[@]}"
}

但是这会导致find抛出一个未知的 predicate 错误:'-not -path foo/*'
有没有办法做到这一点?当我回显命令时,它看起来是正确的,但一定有一些bash语法规则导致它不能按我期望的方式工作。
更新:
我在路径周围添加了\"以排除,因为我读到globbing只发生在带引号的字符串中。xtrace显示如下:

find . -name hvr.yml -not -path '"foo/*"' -not -path '"bar/*"'

单引号可能是问题所在
删除\"并运行xtrace显示,globbing正在for循环中应用,结果是:

find . -name hvr.yml -not -path "foo/fileinfoo" "foo/somethingelseinfoo" -not -path "bar/*" "bar/fileinbar" "bar/otherfilesinbar"

所以find在抱怨随机路径作为参数。
有没有办法扩展EXCLUDE数组并在命令中的每个元素的末尾添加/*?

3yhwsihp

3yhwsihp1#

找到了一个替代解决方案,我试图通过使用grep来实现:

EXCLUDE=("abc" "def")

getPaths() {
    local exclude_count=${#EXCLUDE[@]}
    if [ $exclude_count -eq 0 ]; then
        find . -name $FILENAME | tr '\n' ' '
        return $?
    fi

    # Concat excluded servers as grep regex
    local regex="(${EXCLUDE[0]}"
    for ((i=1;i<exclude_count;i++)); do
        regex="${regex}|${EXCLUDE[i]}"
    done
    regex="${regex})"

    find . -name $FILENAME | grep -Ev "${regex}" | tr '\n' ' '
    return $?
}
  • 如果exclude为空,则运行正常的find命令。
  • 否则,它会构建一个正则表达式,让grep过滤掉,结果看起来像(abc| def)对于这个例子。
doinxwow

doinxwow2#

#!/bin/bash

getPaths() {
    local ROOT=$1
    local FILEFILTER=$2
    local excluded_folders=("${@:3}")
    
    local exclude_count=${#excluded_folders[@]}
    
    if [ $exclude_count -eq 0 ]; then
        find $ROOT -name $FILEFILTER
        return $?
    fi

    # Concat excluded servers as grep regex
    local regex="(${excluded_folders[0]}"
    for ((i=1;i<exclude_count;i++)); do
        regex="${regex}|${excluded_folders[i]}"
    done
    #append last )
    regex="${regex})"
    
    find $ROOT -name $FILEFILTER -print0 | grep -zZEv "${regex}" | tr '\0' '\n'
    
    return $?
}

# Define excluded folders in a string array
excluded_folders=(
  "/videos/test2" "/videos/test3"
)

inputFiles=()
readarray -t inputFiles < <(getPaths "/videos" "*.ts")
echo "found files using no exclude folders:"
echo "num files=${#inputFiles[@]}"
printf '%s\n' "${inputFiles[@]}"

echo ""

echo "exclude folders:"
printf '%s\n' "${excluded_folders[@]}"

echo ""

inputFiles=()
readarray -t inputFiles < <(getPaths "/videos" "*.ts" "${excluded_folders[@]}")
echo "found files using exclude folders:"
echo "num files=${#inputFiles[@]}"
printf '%s\n' "${inputFiles[@]}"

echo ""

输出:

found files using no exclude folders:
num files=8
/videos/Pointer/Pointer_20230504_13241356.ts
/videos/Top movies/The Treasure of the Sierra Madre_20230504_14201655.ts
/videos/Top movies/Dunkirk_20230504_20252233.ts
/videos/test2/test.ts
/videos/A small light/A small light_20230504_20302130.ts
/videos/A small light/A small light_20230504_21302240.ts
/videos/test3/test3-HD.ts
/videos/test3/testje/test3-HD.ts

exclude folders:
/videos/test2
/videos/test3

found files using exclude folders:
num files=5
/videos/Pointer/Pointer_20230504_13241356.ts
/videos/Top movies/The Treasure of the Sierra Madre_20230504_14201655.ts
/videos/Top movies/Dunkirk_20230504_20252233.ts
/videos/A small light/A small light_20230504_20302130.ts
/videos/A small light/A small light_20230504_21302240.ts

相关问题