Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set, alter or unset envionment variable in execute #2976

Closed
6 of 10 tasks
Kabouik opened this issue Sep 20, 2022 · 2 comments
Closed
6 of 10 tasks

Set, alter or unset envionment variable in execute #2976

Kabouik opened this issue Sep 20, 2022 · 2 comments
Labels

Comments

@Kabouik
Copy link

Kabouik commented Sep 20, 2022

  • I have read through the manual page (man fzf)
  • I have the latest version of fzf
  • I have searched through the existing issues

Info

  • OS
    • Linux
    • Mac OS X
    • Windows
    • Etc.
  • Shell
    • bash
    • zsh
    • fish

Problem / Steps to reproduce

This may not be an issue but I haven't been able to find any hit in my searches in the existing issues or in the manual.

My fzf selection goes into a variable named $selection, which I later re-use in another command. However, I would be interested in having a choice between that command and an alteration of it with an extra argument, and ideally I would like that to be bound to a secondary fzf keybinding instead of forcing the user to add an extra argument beforehand when executing the script. Is it possible to use something like the following?

  • --bind="ctrl-s:execute(extraarg='toto')+accept"
  • --bind="ctrl-s:execute(extraarg='')+accept"
  • --bind="ctrl-s:execute(unset extraarg)+accept"

And then run mycommand $extraarg $selection?

I have tried creating the variable in the execute function, altering a pre-existing variable, using in execute a Bash function defined in the script that sets the variable, or unset extraarg, but so far all my attempts have failed.

My use case here would be a script for password-store, with Return to copy the password to clipboard, and ctrl-s to show it (i.e., pass show --clip $selection vs. pass show $selection). It could also be useful for environment variables that may only be useful for some uses, like LD_LIBRARY_PATH or GDK_SCALE.

@junegunn
Copy link
Owner

execute starts the command as a child process. Any environment variable set in a child process is lost once it terminates. You'll have to store the state externally. e.g. --bind="ctrl-s:execute-silent(echo toto > /tmp/extraarg)+accept"

@Kabouik
Copy link
Author

Kabouik commented Sep 22, 2022

Thanks @junegunn, that works. For reference, below is the passfzf script I came up with:

#!/usr/bin/env bash
# This script unlocks the pass tomb, if any, and then relies on fzf to either
# copy the password to the clipboard or show the content of the .gpg file.
# Author: Kabouik
# Dependencies: fzf, fd, pass

store="$HOME/.password-store/"
swapfile="/swap/swapfile" # Set path to any swapfile not listed in /etc/fstab

# Open pass tomb, if any
if [[ -e "$HOME/.password.tomb" ]]; then
    sudo swapoff -a && sudo swapoff "${swapfile}" 2> /dev/null
    pass open 2> /dev/null
fi

# Select pass entry
main() {
    while :; do
        clear
        selection=$(fd .gpg ~/.password-store/ -d 8 \
                      | fzf --query "${tmp}" \
                            --prompt="# " \
                            --ansi \
                            --extended \
                            --no-border \
                            --with-nth 5.. \
                            --delimiter "/" \
                            --layout=reverse-list \
                            --no-multi \
                            --cycle \
                            --header='
Ret: copy, C-s: show, C-e: edit, C-a: add, C-d: delete,
C-r: create and copy new random password,
M-g: git push, C-g: git pull,
C-c/Esc: clear query or exit' \
                            --margin='1,2,1,2' \
                            --color='16,gutter:-1' \
                            --bind="tab:down" \
                            --bind="btab:up" \
                            --bind="ctrl-s:execute(echo 'show' > /tmp/passfzfarg)+accept" \
                            --bind="ctrl-e:execute(echo 'edit' > /tmp/passfzfarg)+accept" \
                            --bind="ctrl-a:execute(echo 'add' > /tmp/passfzfarg)+print-query" \
                            --bind="ctrl-d:execute(echo 'rm' > /tmp/passfzfarg)+accept" \
                            --bind="ctrl-r:execute(echo 'generate --clip' > /tmp/passfzfarg)+print-query" \
                            --bind="alt-g:abort+execute(echo 'git push -u --all' > /tmp/passfzfarg)" \
                            --bind="ctrl-g:abort+execute(echo 'git pull' > /tmp/passfzfarg)" \
                            --bind="ctrl-c:execute(echo 'quit' > /tmp/passfzfarg)+cancel" \
                            --bind="esc:execute(echo 'quit' > /tmp/passfzfarg)+cancel")

        if [[ -f "/tmp/passfzfarg" ]]; then
            arg=$(cat /tmp/passfzfarg)
            rm /tmp/passfzfarg
        else
            arg="show --clip"
        fi

        if ! [[ -v "$selection" ]]; then
            clear
            case "$arg" in
                add)
                    printf "\033[0;32mNew password Directory/Name:\033[0m ${selection}"
                    if [[ -n "$selection" ]]; then
                        printf "\033[0;32m\nPress Return to confirm or type new Directory/Name:\033[0m "
                    fi
                    read -r
                    tmp="${REPLY:=$selection}"
                    pass ${arg} "${tmp}"
                    continue
                    ;;
                "generate --clip")
                    printf "\033[0;32mNew password Directory/Name:\033[0m ${selection}"
                    if [[ -n "$selection" ]]; then
                        printf "\033[0;32m\nPress Return to confirm or type new Directory/Name:\033[0m "
                    fi
                    read -r
                    tmp="${REPLY:=$selection}"
                    printf "\033[0;32mNumber of characters:\033[0m "
                    read -r
                    pass ${arg} --in-place "${tmp}" "${REPLY}" \
                        2> /dev/null || pass ${arg} "${tmp}" "${REPLY}"
                    printf "\nPress any key to continue. "
                    read -rsn1
                    continue
                    ;;
                quit)
                    pkill -P $$
                    return
                    ;;
                *)
                    if [[ -n "$selection" ]]; then
                        tmp=${selection::-4} && tmp=${tmp#"$store"}
                        pass ${arg} "${tmp}"
                    else
                        pass ${arg}
                    fi
                    printf "\nPress any key to continue. "
                    read -rsn1
                    continue
                    ;;
            esac
        fi
    done
}

main

# Close pass tomb, if any
if [[ -e "$HOME/.password.tomb" ]]; then
    printf "\n"
    pass close
    sudo swapon -a && sudo swapon "${swapfile}" 2> /dev/null
fi

printf "\nPress any key to quit. " && read -rsn1

There are already some pass extensions that do similar things, but they are not available for all distributions and I prefer using a simple shell script I can customize instead of depending on an extension. It seems to work well so far.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants