pashage

Yet Another Opinionated Re-engineering of the Unix Password Store
git clone https://git.instinctive.eu/pashage.git
Log | Files | Refs | README | LICENSE

commit 2a562f1e1d852068ecd6501929e1b8f6d62f5c0f
parent 094404790dee16a61d257a8b26123e291d42e230
Author: Natasha Kerensikova <natgh@instinctive.eu>
Date:   Sat,  1 Nov 2025 18:19:01 +0000

Raw list output is rewritten without subshell

This leads to a 2x speed improvement (from 55 to 25 ms for my store in my machine).
Diffstat:
Mspec/action_spec.sh | 24++++++++++++------------
Msrc/pashage.sh | 82++++++++++++++++++++++++++++++-------------------------------------------------
2 files changed, 43 insertions(+), 63 deletions(-)

diff --git a/spec/action_spec.sh b/spec/action_spec.sh @@ -1797,11 +1797,11 @@ Describe 'Action Functions' It 'displays everything without a pattern' result() { %text - #|Base/other/lower - #|Base/root - #|Base/subdir/subsub/old + #|other/lower + #|root + #|subdir/subsub/old } - When call do_list "${PREFIX}" 'Base/' + When call do_list '' The status should be success The output should equal "$(result)" End @@ -1809,22 +1809,22 @@ Describe 'Action Functions' It 'displays only matching files' result() { %text - #|Base/other/lower - #|Base/subdir/subsub/old + #|other/lower + #|subdir/subsub/old } - When call do_list "${PREFIX}" 'Base/' -i L + When call do_list '' -i L The status should be success The output should equal "$(result)" End It 'does not display matching directories' - When call do_list "${PREFIX}" 'Base/' t + When call do_list '' t The status should be success - The output should equal 'Base/root' + The output should equal 'root' End It 'might not display anything' - When call do_list "${PREFIX}" 'Base/' z + When call do_list '' z The status should be success The output should equal '' End @@ -1872,7 +1872,7 @@ Describe 'Action Functions' When call do_list_or_show '' The status should be success The output should be blank - The error should equal "$ do_list ${PREFIX} " + The error should equal "$ do_list " End It 'lists the whole store as a tree' @@ -1910,7 +1910,7 @@ Describe 'Action Functions' When call do_list_or_show 'subdir' The status should be success The output should be blank - The error should equal "$ do_list ${PREFIX}/subdir subdir/" + The error should equal "$ do_list subdir" End It 'lists a subdirectory as a tree' diff --git a/src/pashage.sh b/src/pashage.sh @@ -848,58 +848,38 @@ do_insert() { } # Display the entry list rooted at the given relative directory -# $1: root directory -# $2: path prefix +# $1: path relative to prefix # ...: (optional) grep arguments to filter +# Note that this function is recrusive and cannot use variables to hold state. do_list() { - ( cd "$1" && shift && do_list_cwd "$@" ) -} - -# Display an entry list -# $1: path prefix -# ...: (optional) grep arguments to filter -do_list_cwd() { - LIST_PREFIX="$1" - shift - - for ENTRY in *; do - [ -e "${ENTRY}" ] || continue - do_list_item "${ENTRY}" "${LIST_PREFIX}" "$@" - done - unset ENTRY - - unset LIST_PREFIX -} - -# Display an entry in a list -# $1: item name -# $2: full item path -# ...: (optional) grep arguments to filter -do_list_item() { - ITEM_NAME="$1" - ITEM_PATH="$2" - shift 2 - - if [ -d "${ITEM_NAME}" ]; then - do_list "${ITEM_NAME}" \ - "${ITEM_PATH}${ITEM_NAME}/" \ - "$@" - elif [ "${ITEM_NAME%.age}.age" = "${ITEM_NAME}" ]; then - if [ $# -eq 0 ] \ - || printf '%s\n' "${ITEM_NAME%.age}" | grep -q "$@" - then - printf '%s%s\n' "${ITEM_PATH}" "${ITEM_NAME%.age}" - fi - elif [ "${ITEM_NAME%.gpg}.gpg" = "${ITEM_NAME}" ]; then - if [ $# -eq 0 ] \ - || printf '%s\n' "${ITEM_NAME%.age}" | grep -q "$@" - then - printf '%s%s\n' "${ITEM_PATH}" "${ITEM_NAME%.gpg}" + for FULL_ENTRY in "${PREFIX}/$1${1:+/}"*; do + ENTRY="${FULL_ENTRY#"${PREFIX}/"}" + ITEM_NAME="${ENTRY##*/}" + if [ -d "${FULL_ENTRY}" ]; then + shift + set -- "${ENTRY}" "$@" + do_list "$@" + elif [ "${ENTRY%.age}.age" = "${ENTRY}" ]; then + shift + set -- "-q" "$@" + if [ $# -le 1 ] \ + || printf '%s\n' "${ITEM_NAME%.age}" | grep "$@" + then + printf '%s\n' "${ENTRY%.age}" + fi + elif [ "${ENTRY%.gpg}.gpg" = "${ENTRY}" ]; then + shift + set -- "-q" "$@" + if [ $# -le 1 ] \ + || printf '%s\n' "${ITEM_NAME%.gpg}" | grep "$@" + then + printf '%s\n' "${ENTRY%.gpg}" + fi fi - fi - - unset ITEM_NAME - unset ITEM_PATH + unset ENTRY + unset ITEM_NAME + done + unset FULL_ENTRY } # Display a single directory or entry @@ -908,7 +888,7 @@ do_list_item() { do_list_or_show() { if [ -z "$1" ]; then if [ "${LIST_VIEW-no}" = "yes" ]; then - do_list "${PREFIX}" "" + do_list '' else do_tree "${PREFIX}" "Password Store" fi @@ -920,7 +900,7 @@ do_list_or_show() { unset SECRET elif [ -d "${PREFIX}/$1" ]; then if [ "${LIST_VIEW-no}" = "yes" ]; then - do_list "${PREFIX}/$1" "${1%/}/" + do_list "${1%/}" else do_tree "${PREFIX}/$1" "$1" fi