shell-script-pt
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[shell-script-pt] Como iterar um array recursivo sem redundância?


From: Vilmar Catafesta
Subject: [shell-script-pt] Como iterar um array recursivo sem redundância?
Date: Wed, 11 Nov 2020 19:24:09 -0400

Olá shelleiros, saudações

Tenho em determinado diretório, milhares de arquivos de pacote de software, que por sua vez tem versões, como por exemplo:

/var/cache/fetch/archives/python-3.5.0-1-x86_64.chi.zst
/var/cache/fetch/archives/python-3.8.6-1-x86_64.chi.zst
/var/cache/fetch/archives/python-3.8.6-2-x86_64.chi.zst
/var/cache/fetch/archives/nano-5.0-1-x86_64.chi.zst
/var/cache/fetch/archives/nano-5.2-1-x86_64.chi.zst
/var/cache/fetch/archives/nano-5.3-1-x86_64.chi.zst

A cada nova versão, necessito compilar e empacotar os mesmos, removendo as versão mais antigas do diretório, o qual escrevi esse script abaixo para a função de remover as versões mais antigas, deixando somente a versão mais atual.

#!/usr/bin/bash

aPKGSPLIT=()
cachedirs=("/var/cache/fetch/archives")
pkg_ext='.chi.zst'
pkg_re='(.+)-(([^-]+)-([0-9]+))-([^.]+)\.chi\.zst'
: ${aPKGSPLIT=()}
: ${aPKGLIST=}
: ${PKG_FOLDER_DIR=0}
: ${PKG_FULLNAME=1}
: ${PKG_ARCH=2}
: ${PKG_BASE=3}
: ${PKG_BASE_VERSION=4}
: ${PKG_VERSION=5}
: ${PKG_BUILD=6}

function die(){
    local msg=$1; shift
   printf "%s %s\n" "$msg" "$@" >&2
    exit 1
}

sh_splitpkg(){
    local file=${1}
    local pkg_folder_dir=$(echo ${file%/*})
    local pkg_fullname=$(echo ${file##*/})
    local   pkg_base=
    local   pkg_version_build=
    local   pkg_version=
    local   pkg_build=
    local   pkg_arch=
    local   pkg_base_version=

    [[ $pkg_fullname =~ $pkg_re ]] &&
        pkg_fullname=${BASH_REMATCH[0]}
        pkg_base=${BASH_REMATCH[1]}
        pkg_version_build=${BASH_REMATCH[2]}
        pkg_version=${BASH_REMATCH[3]}
        pkg_build=${BASH_REMATCH[4]}
        pkg_arch=${BASH_REMATCH[5]}
        pkg_base_version=${pkg_base}-${pkg_version_build}

    aPKGSPLIT=($pkg_folder_dir $pkg_fullname $pkg_arch $pkg_base $pkg_base_version $pkg_version $pkg_build)
    return $?
}

main(){
    local pkg=
    local pkgInAll=
    local pkg_base=
    local pkg_search=
    local candidates=()
    local cachedir

    for cachedir in "${cachedirs[@]}"
    do
        [[ -d $cachedir ]]            || die "Error: cachedir '$cachedir' does not exist or is not a directory"
        pushd "$cachedir" &>/dev/null || die "Error: failed to chdir to $cachedir"

        while read -r pkgInAll;do
            sh_splitpkg ${pkgInAll}
            pkg_base=${aPKGSPLIT[$PKG_BASE]}

            [[ -z "$pkg_base" ]] && continue

            while read -r pkg;do
                sh_splitpkg ${pkg}
                pkg_search=${aPKGSPLIT[$PKG_BASE]}

                [[ -z "$pkg_search" ]] &&   continue
                [[ "${pkg_search::1}" > "${pkg_base::1}" ]] && break

                if [[ "${pkg_base}" =~ "${pkg_search}" ]] && [[ "$(vercmp $pkgInAll $pkg)" -lt 0 ]]; then
                    printf "%s\n" "${pkgInAll}"
                    candidates+=("${pkgInAll}")
                fi
            done < <(printf '%s\n' "$(find "$PWD" -type f -name "$pkg_base*.zst" | grep -E "*$pkg_base-([0-9])" | sort)")
        done < <(printf '%s\n' "$(find "$PWD" -type f -name "*.chi.zst" | sort)")
        popd >/dev/null 2>&1
    done

Tenho em determinado diretório, milhares de arquivos de pacote de software, que por sua vez tem versões, como por exemplo:

/var/cache/fetch/archives/python-3.5.0-1-x86_64.chi.zst
/var/cache/fetch/archives/python-3.8.6-1-x86_64.chi.zst
/var/cache/fetch/archives/python-3.8.6-2-x86_64.chi.zst
/var/cache/fetch/archives/nano-5.0-1-x86_64.chi.zst
/var/cache/fetch/archives/nano-5.2-1-x86_64.chi.zst
/var/cache/fetch/archives/nano-5.3-1-x86_64.chi.zst

A cada nova versão, necessito compilar e empacotar os mesmos, removendo as versão mais antigas do diretório, o qual escrevi esse script abaixo para a função de remover as versões mais antigas, deixando somente a versão mais atual.

#!/usr/bin/bash

aPKGSPLIT=()
cachedirs=("/var/cache/fetch/archives")
pkg_ext='.chi.zst'
pkg_re='(.+)-(([^-]+)-([0-9]+))-([^.]+)\.chi\.zst'
: ${aPKGSPLIT=()}
: ${aPKGLIST=}
: ${PKG_FOLDER_DIR=0}
: ${PKG_FULLNAME=1}
: ${PKG_ARCH=2}
: ${PKG_BASE=3}
: ${PKG_BASE_VERSION=4}
: ${PKG_VERSION=5}
: ${PKG_BUILD=6}

function die(){
    local msg=$1; shift
   printf "%s %s\n" "$msg" "$@" >&2
    exit 1
}

sh_splitpkg(){
    local file=${1}
    local pkg_folder_dir=$(echo ${file%/*})
    local pkg_fullname=$(echo ${file##*/})
    local   pkg_base=
    local   pkg_version_build=
    local   pkg_version=
    local   pkg_build=
    local   pkg_arch=
    local   pkg_base_version=

    [[ $pkg_fullname =~ $pkg_re ]] &&
        pkg_fullname=${BASH_REMATCH[0]}
        pkg_base=${BASH_REMATCH[1]}
        pkg_version_build=${BASH_REMATCH[2]}
        pkg_version=${BASH_REMATCH[3]}
        pkg_build=${BASH_REMATCH[4]}
        pkg_arch=${BASH_REMATCH[5]}
        pkg_base_version=${pkg_base}-${pkg_version_build}

    aPKGSPLIT=($pkg_folder_dir $pkg_fullname $pkg_arch $pkg_base $pkg_base_version $pkg_version $pkg_build)
    return $?
}

main(){
    local pkg=
    local pkgInAll=
    local pkg_base=
    local pkg_search=
    local candidates=()
    local cachedir

    for cachedir in "${cachedirs[@]}"
    do
        [[ -d $cachedir ]]            || die "Error: cachedir '$cachedir' does not exist or is not a directory"
        pushd "$cachedir" &>/dev/null || die "Error: failed to chdir to $cachedir"

        while read -r pkgInAll;do
            sh_splitpkg ${pkgInAll}
            pkg_base=${aPKGSPLIT[$PKG_BASE]}

            [[ -z "$pkg_base" ]] && continue

            while read -r pkg;do
                sh_splitpkg ${pkg}
                pkg_search=${aPKGSPLIT[$PKG_BASE]}

                [[ -z "$pkg_search" ]] &&   continue
                [[ "${pkg_search::1}" > "${pkg_base::1}" ]] && break

                if [[ "${pkg_base}" =~ "${pkg_search}" ]] && [[ "$(vercmp $pkgInAll $pkg)" -lt 0 ]]; then
                    printf "%s\n" "${pkgInAll}"
                    candidates+=("${pkgInAll}")
                fi
            done < <(printf '%s\n' "$(find "$PWD" -type f -name "$pkg_base*.zst" | grep -E "*$pkg_base-([0-9])" | sort)")
        done < <(printf '%s\n' "$(find "$PWD" -type f -name "*.chi.zst" | sort)")
        popd >/dev/null 2>&1
    done

    if (( ! ${#candidates[*]} )); then
        die "NO packages found for pruning"
    fi
}

main $*

O script cumpre bem a tarefa, pecando somente na questão de rapidez, sendo que são milhares de pacotes a processar, pois necessário verificar individualmente cada um deles com outro pacote para saber qual versão é mais atual.

Alguma ideia para melhorar a rapidez dessa busca?

nessa parte do código foi usado o find, pois os pacotes também se encontram em subdiretórios:

done < <(printf '%s\n' "$(find "$PWD" -type f -name "*.chi.zst" | sort)")

O cerne da questão é de como melhorar esse processamento abaixo:

    while read -r pkgInAll;do
        sh_splitpkg ${pkgInAll}
        pkg_base=${aPKGSPLIT[$PKG_BASE]}

        [[ -z "$pkg_base" ]] && continue

        while read -r pkg;do
            sh_splitpkg ${pkg}
            pkg_search=${aPKGSPLIT[$PKG_BASE]}

            [[ -z "$pkg_search" ]] &&   continue
            [[ "${pkg_search::1}" > "${pkg_base::1}" ]] && break

            if [[ "${pkg_base}" =~ "${pkg_search}" ]] && [[ "$(vercmp $pkgInAll $pkg)" -lt 0 ]]; then
                printf "%s\n" "${pkgInAll}"
                candidates+=("${pkgInAll}")
            fi
        done < <(printf '%s\n' "$(find "$PWD" -type f -name "$pkg_base*.zst" | grep -E "*$pkg_base-([0-9])" | sort)")
    done < <(printf '%s\n' "$(find "$PWD" -type f -name "*.chi.zst" | sort)")


reply via email to

[Prev in Thread] Current Thread [Next in Thread]