跳过查找中的项目直到达到(或通过)路径

时间:2014-08-17 18:11:28

标签: shell find

我有一个长时间运行的脚本,它处理从find语句返回的大量文件,并定期存储最近处理的路径。这允许脚本在后续运行时尝试从该路径后恢复。

目前,我正在通过运行已排序的find来执行此操作,直到我到达的路径等于或大于处理的最后一个路径。

例如:

#!/bin/bash
tmp_dir=$(mktemp -d "/tmp/tmp.$$.XXXXXX")
trap 'rm -R "$tmp_dir"; echo "$last_path" > ~/.last_path;' INT HUP TERM EXIT

last_path=$(cat ~/.last_path)
mkfifo "$tmp_dir/files"
{ find -s . -mindepth 1 -type f -print0; printf '\0'; } > "$tmp_dir/files" &
exec 5< "$tmp_dir/files"

next() { read -rd '' path <&5; }
next

if [ -n "$last_path" ]; then
    while [[ "$path" < "$last_path" || "$path" = "$last_path" ]]; do
        next
        [ -z "$path" ] && break
    done

    if [ -n "$path" ]; then
        echo "Ready to resume from: $path"
    else
        echo 'Unable to resume (start from beginning next time)'
        last_path=
        exit
    fi
fi

while [ -n "$path" ]; do
    echo "$path"
    last_path="$path"
    next
done
last_path=

正如您所看到的,脚本将尝试确保最后一条路径始终写在~/.last_path的文件中,当它启动时,它会查看是否应该恢复。如果它应该然后它将运行find命令的内容,直到它找到第一个路径(按字母顺序,由于排序)与最后一个路径相比,以便它可以从这里恢复。 / p>

无论如何,这适用于较小的文件集,但对于较大的集合并不是特别有效,因为一个十万个文件的恢复路径需要很长的延迟,直到搜索到达该点并且可以再次恢复

我的想法是在-prune命令中使用find操作,以便删除不可能包含恢复路径的层次结构块,但是我无法搞清楚最好的方法。

例如,我最初想过做类似的事情:

-exec [[ {} < "$last_path" ]] -prune

但是,如果我想要达到/foo/bar的路径,那么上述规则会修剪/foo,这使得这不可能。

2 个答案:

答案 0 :(得分:1)

{ find -ds . -mindepth 1 -type f -print0; printf '\0'; } > "$tmp_dir/files"

上面的代码实际上会立即将find的所有输出写入"$tmp_dir/files"。不确定fifo管道是否允许一次全部保持。没有其他阅读输入它甚至可以工作吗?

由于您正在使用Bash,您最好采用的是使用进程替换。无需使用命名管道。

exec 5< <(exec find -ds . -mindepth 1 -type f -print0)

如果$path不为空,也可以在不进行测试的情况下完成代码的某些部分:

while
    echo "$path"
    last_path=$path
    next
do
    :
done

last_path=$(cat ~/.last_path)也可以只是IFS= read -r last_path < ~/.last_path

如果您想存储和阅读不规则路径:

printf '%s\0' "$last_path" > ~/.last_path
IFS= read -rd '' < ~/.last_path

答案 1 :(得分:1)

啊哈!我想我可能已经使用自定义函数找到了解决方案:

skip_path() {
    path="$1"; skip="$2"
    if [ -d "$path" ]; then
        length=${#path}
        skip=${skip:0:$length}
    fi
    [[ "$path" < "$skip" ]]; return $?
}

然后可以这样调用:

export -f skip_path
find -s . -mindepth 1 -exec bash -c 'skip_path "$@"' -- {} "$last_path" \; -prune -or -type f -print0;
似乎要做的伎俩! last_path 必须来自find的输出是没有价值的,即它必须在形式上与find使用的路径相同。因此,如果find以相对路径运行,它通常会返回“./foo/bar”形式的路径,因此“{foo / bar”的last_path将不起作用,实际上导致跳过所有内容,因此请注意从last_path开始的地方!