From 1b4c1b65d09a1072175e77b3174fd3415c40a0d5 Mon Sep 17 00:00:00 2001 From: zawz Date: Fri, 27 Nov 2020 16:22:44 +0100 Subject: [PATCH] Remove zpass --- README.md | 3 +- zpass/Makefile | 16 ------- zpass/src/archive.sh | 101 ----------------------------------------- zpass/src/cache.sh | 38 ---------------- zpass/src/clipboard.sh | 45 ------------------ zpass/src/config.sh | 46 ------------------- zpass/src/crypt.sh | 56 ----------------------- zpass/src/file.sh | 13 ------ zpass/src/help.sh | 46 ------------------- zpass/src/main.sh | 34 -------------- zpass/src/operation.sh | 75 ------------------------------ zpass/src/prompt.sh | 62 ------------------------- zpass/src/util.sh | 60 ------------------------ 13 files changed, 1 insertion(+), 594 deletions(-) delete mode 100644 zpass/Makefile delete mode 100644 zpass/src/archive.sh delete mode 100644 zpass/src/cache.sh delete mode 100644 zpass/src/clipboard.sh delete mode 100644 zpass/src/config.sh delete mode 100644 zpass/src/crypt.sh delete mode 100644 zpass/src/file.sh delete mode 100644 zpass/src/help.sh delete mode 100644 zpass/src/main.sh delete mode 100644 zpass/src/operation.sh delete mode 100644 zpass/src/prompt.sh delete mode 100644 zpass/src/util.sh diff --git a/README.md b/README.md index 9320070..66ac76d 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,9 @@ Various CLI Shell tools - [zdate](/zdate) : Date operations on folders recursively - [zdesktop](/zdesktop) : Generate and manage desktop files - [zgoc](/zgoc) : Overclocking for AMD GPUs -- [znotif](/znotif) : Notifications on end of commands +- [znotif](/znotif) : Desktop notifications - [zosu](/zosu) : Osu installer/manager for linux - [zpac](/zpac) : Pulseaudio tool for volume management -- [zpass](/zpass) : Simple CLI password manager - [zrct2](/zrct2) : OpenRCT2 install/server utilities - [zsmc](/zmc) : Minecraft server utilities - [zsync](/zmc) : Simple server/client file sync diff --git a/zpass/Makefile b/zpass/Makefile deleted file mode 100644 index ff51bb0..0000000 --- a/zpass/Makefile +++ /dev/null @@ -1,16 +0,0 @@ - -var_exclude = ZPASS_.* XDG_.* REMOTE_.* DISPLAY CONFIGFILE TMPDIR - -zpass: src/* - lxsh -o zpass -m --minimize-var --exclude-var "$(var_exclude)" --minimize-fct --remove-unused src/main.sh - -build: zpass - -install: build - cp zpass /usr/local/bin - -uninstall: - rm /usr/local/bin/zpass - -clear: - rm zpass diff --git a/zpass/src/archive.sh b/zpass/src/archive.sh deleted file mode 100644 index 45f423d..0000000 --- a/zpass/src/archive.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/sh - -# $1 = tmpdir , $2 = keyfile -unpack() { - rm -rf "$1" || return $? - mkdir -p "$1" || return $? - ( - set -e - cd "$1" - decrypt "$2" | tar -xf - 2>/dev/null - ) -} - -# $1 = tmpdir , $2 = keyfile -pack() -{ - # clean empty dirs - archive="archive_$(randalnum 5)" - ( - cd "$1" || exit $? - if [ -n "$2" ] - then - key=$(cat "$2") && rm "$2" || exit $? - else - key=$(new_key_with_confirm) || exit $? - fi - tar -cf - -- * | encrypt "$key" > "$1/$archive" || exit $? - ) || return $? - if [ -n "$ZPASS_REMOTE_ADDR" ] - then - [ -z "$ZPASS_PATH" ] && datapath="~/.local/share/zpass" - if [ -n "$ZPASS_SSH_ID" ] - then scp -i "$ZPASS_SSH_ID" "$1/$archive" "$ZPASS_REMOTE_ADDR:$datapath/$ZPASS_FILE$ZPASS_EXTENSION" >/dev/null || return $? - else scp "$1/$archive" "$ZPASS_REMOTE_ADDR:$datapath/$ZPASS_FILE$ZPASS_EXTENSION" >/dev/null || return $? - fi - rm -f "$1/$archive" 2>/dev/null - return 0 - else - mv -f "$1/$archive" "$file" - fi -} - -# $@ = command to execute inside archive -# set env __NOPACK to not repack after command -archive_exec() -{ - err=0 - # tmp files - tmpdir="$TMPDIR/zpass_$(randalnum 5)" - keyfile="$tmpdir/$(randalnum 5).key" - # operation - ( - # unpack - unpack "$tmpdir/archive" "$keyfile" || exit $? - # execute - (cd "$tmpdir/archive" && "$@") || exit $? - # repack - [ -z "$__NOPACK" ] && { pack "$tmpdir/archive" "$keyfile" || exit $?; } - exit 0 - ) || err=$? - # cleanup - rm -rf "$tmpdir" - return $err -} - -# no argument -create() { - if [ -f "$file" ] - then - tmpdir="$TMPDIR/zpass_$(randalnum 5)" - # pack n repack with no tmp key: create new - unpack "$tmpdir" || return $? - pack "$tmpdir" || { echo "Encryption error" >&2 && return 1 ; } - rm -rf "$tmpdir" - else - # if remote: file tmp - [ -n "$ZPASS_REMOTE_ADDR" ] && { - file="$TMPDIR/zpass_$(filehash)$ZPASS_EXTENSION" - } - # get key - [ -z "$ZPASS_KEY" ] && { - ZPASS_KEY=$(new_key_with_confirm) || { echo "Cancelled" >&2 && return 100 ; } - } - # create archive - tar -cf - -T /dev/null | encrypt "$ZPASS_KEY" > "$file" || { - echo "Encryption error" >&2 - # echo "$tmperr" >&2 - rm "$file" - return 1 - } - [ -n "$ZPASS_REMOTE_ADDR" ] && { - ssh "$ZPASS_REMOTE_ADDR" "mkdir -p '$datapath'" - if [ -n "$ZPASS_SSH_ID" ] - then scp -i "$ZPASS_SSH_ID" "$file" "$ZPASS_REMOTE_ADDR:$datapath/$ZPASS_FILE$ZPASS_EXTENSION" >/dev/null || return $? - else scp "$file" "$ZPASS_REMOTE_ADDR:$datapath/$ZPASS_FILE$ZPASS_EXTENSION" >/dev/null || return $? - fi - rm -rf "$file" 2>/dev/null - } - fi - return 0 -} diff --git a/zpass/src/cache.sh b/zpass/src/cache.sh deleted file mode 100644 index bf67c77..0000000 --- a/zpass/src/cache.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -## Cache functions - -clear_cache() { - rm "$cachepath"/* -} - -write_cache() { - echo "$1" > "$cachepath/$(keyfile)" - delete_cache "$ZPASS_KEY_CACHE_TIME" -} - -get_key_cached() { - [ ! -f "$file" ] && return 0 - cat "$cachepath/$(keyfile)" 2>/dev/null -} - -# $1 = delay in sec -delete_cache() { - if [ "$1" -gt 0 ] 2>/dev/null - then - for I in $(screen -ls | grep "zpass_$(keyfile)" | awk '{print $1}') - do - screen -S "$I" -X stuff "^C" - done - screen -dmS "zpass_$(keyfile)" sh -c "sleep $1 ; $0 rmc" # call zpass with cache delete - else - rm -f "$cachepath/$(keyfile)" 2>/dev/null - fi -} - -clean_cache() { - # key cache - find "$cachepath" -type f ! -newermt @$(date -d "-$ZPASS_KEY_CACHE_TIME seconds" +%s) -print0 | xargs -0 rm - # tmp folders older than 5 min - rm -rd $(find "$TMPDIR" -maxdepth 1 -type d -name 'zpass_*' ! -mmin 5) -} diff --git a/zpass/src/clipboard.sh b/zpass/src/clipboard.sh deleted file mode 100644 index 8db7bf8..0000000 --- a/zpass/src/clipboard.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -clipboard() -{ - unset in - read -r in - while read -r ln - do - in="$in -$ln" - done - printf "%s" "$in" | xclip -selection clipboard - which wl-copy >/dev/null 2>&1 && printf "%s" "$in" | wl-copy -} - -# $1 = delay in sec -clipboard_clear() { - if [ -n "$1" ] - then - for I in $(screen -ls | grep "$fname"_clipboard | awk '{print $1}') - do - screen -S "$I" -X stuff "^C" - done - screen -dmS "$fname"_clipboard sh -c "sleep $1 - xclip -selection clipboard < /dev/null - which wl-copy 2>&1 && wl-copy < /dev/null - sleep 1" - else - echo | clipboard - fi -} - -copy_check() -{ - if ps -e | grep -qi wayland - then - which wl-copy >/dev/null 2>&1 || error 1 "ERROR: running wayland but wl-clipboard is not installed" - elif [ -n "$DISPLAY" ] - then - which xclip >/dev/null 2>&1 || error 1 "ERROR: running X but xclip is not installed" - else - error 1 "ERROR: no graphical server detected" - fi - return 0 -} diff --git a/zpass/src/config.sh b/zpass/src/config.sh deleted file mode 100644 index 8998f10..0000000 --- a/zpass/src/config.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -# XDG config/cache -datapath=".local/share/zpass" -cachepath="$HOME/.cache/zpass" -configpath="$HOME/.config/zpass" -[ -n "$XDG_CONFIG_HOME" ] && configpath="$XDG_CONFIG_HOME/zpass" -[ -n "$XDG_CACHE_HOME" ] && cachepath="$XDG_CACHE_HOME/zpass" -[ -z "$CONFIGFILE" ] && CONFIGFILE="$configpath/default.conf" -[ -n "$XDG_DATA_HOME" ] && [ -z "$ZPASS_REMOTE_ADDR" ] && datapath="$XDG_DATA_HOME/zpass" - -[ -z "$TMPDIR" ] && TMPDIR=/tmp - -# stash env config -tmpenv="$TMPDIR/zpassenv_$(randalnum 5)" -env | grep '^ZPASS_.*=' | sed "s/'/'\\\''/g;s/=/='/;s/$/'/g" > "$tmpenv" - -# load config file -[ -f "$CONFIGFILE" ] && { . "$CONFIGFILE" || exit $? ; } - -. "$tmpenv" || exit $? -rm -f "$tmpenv" 2>/dev/null - -# resolve zpass_path -[ -n "$ZPASS_PATH" ] && datapath="$ZPASS_PATH" -[ -n "$ZPASS_CACHE_PATH" ] && cachepath="$ZPASS_CACHE_PATH" - -# default ZPASS config -[ -z "$ZPASS_FILE" ] && ZPASS_FILE=default -[ -z "$ZPASS_EXTENSION" ] && ZPASS_EXTENSION=.tar.gpg -[ -z "$ZPASS_KEY_CACHE_TIME" ] && ZPASS_KEY_CACHE_TIME=60 # in seconds -[ -z "$ZPASS_CLIPBOARD_TIME" ] && ZPASS_CLIPBOARD_TIME=30 # in seconds -[ -z "$ZPASS_UNK_OP_CALL" ] && ZPASS_UNK_OP_CALL=copy -[ -z "$ZPASS_RAND_LEN" ] && ZPASS_RAND_LEN=20 - -# datapath resolution -# remove tildes -datapath="${datapath#\~/}" -[ "$datapath" = '~' ] && datapath="" -# if not remote and not absolute: add HOME -[ -z "$ZPASS_REMOTE_ADDR" ] && [ "$(echo "$datapath" | cut -c1)" != '/' ] && datapath="$HOME/$datapath" - -file="$datapath/$ZPASS_FILE$ZPASS_EXTENSION" - -[ -z "$ZPASS_REMOTE_ADDR" ] && { mkdir -p "$datapath" 2>/dev/null || error 1 "Could not create '$datapath'"; } -mkdir -p "$cachepath" 2>/dev/null && chmod -R go-rwx "$cachepath" 2>/dev/null diff --git a/zpass/src/crypt.sh b/zpass/src/crypt.sh deleted file mode 100644 index 92f7f20..0000000 --- a/zpass/src/crypt.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -# $1 = key -encrypt() { - gpg --pinentry-mode loopback --batch --passphrase "$1" -o - -c - -} - -# $1 = key , $2 = keyfile to write -decrypt_with_key() -{ - gpg --pinentry-mode loopback --batch --passphrase "$1" -o - -d "$file" 2>/dev/null && ret=$? && [ -n "$2" ] && echo "$1" > "$2" - return $ret -} - -# $1 = keyfile to write -decrypt() -{ - # get remote file - [ -n "$ZPASS_REMOTE_ADDR" ] && { - file="$TMPDIR/zpass_$(filehash)$ZPASS_EXTENSION" - [ -z "$ZPASS_PATH" ] && datapath="~/.local/share/zpass" - if [ -n "$ZPASS_SSH_ID" ] - then scp -i "$ZPASS_SSH_ID" "$ZPASS_REMOTE_ADDR:$datapath/$ZPASS_FILE$ZPASS_EXTENSION" "$file" >/dev/null || return $? - else scp "$ZPASS_REMOTE_ADDR:$datapath/$ZPASS_FILE$ZPASS_EXTENSION" "$file" >/dev/null || return $? - fi - } - cat "$file" >/dev/null 2>&1 || { echo "File doesn't exist. Use 'zpass create' to create the file" >&2 && return 1; } # no file - - if [ -n "$ZPASS_KEY" ] - then # key given already - decrypt_with_key "$ZPASS_KEY" "$1" ; ret=$? - else # prompt for key - # attempt decrypt from cache - key=$(get_key_cached) && decrypt_with_key "$key" "$1" - ret=$? - if [ $ret -ne 0 ] - then - # cache was incorrect: delete - delete_cache >/dev/null 2>&1 - # try loop - tries=0 - while [ $ret -ne 0 ] && [ $tries -lt 3 ] - do - key=$(ask_key) || { echo "Cancelled" >&2 && return 100 ; } - tries=$((tries+1)) - decrypt_with_key "$key" "$1" ; ret=$? - done - fi - fi - - # remove temporary file - [ -n "$ZPASS_REMOTE_ADDR" ] && rm -rf "$file" 2>/dev/null - - [ $ret -ne 0 ] && { echo "Could not decrypt '$file'" >&2 ; } - return $ret -} diff --git a/zpass/src/file.sh b/zpass/src/file.sh deleted file mode 100644 index fad9fb7..0000000 --- a/zpass/src/file.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -list_files() { - _cmd_ "cd '$datapath' 2>/dev/null && find . -maxdepth 1 -type f -regex '.*$ZPASS_EXTENSION\$'" | sed 's/$(escape_chars "$ZPASS_EXTENSION")\$//g; s|.*/||g' -} - -remove_files() -{ - for N - do - _cmd_ "rm '$datapath/$N$ZPASS_EXTENSION'" || exit $? - done -} diff --git a/zpass/src/help.sh b/zpass/src/help.sh deleted file mode 100644 index 152c4ac..0000000 --- a/zpass/src/help.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -fname=$(basename "$0") -usage() -{ - echo "$fname [options] -[Global Operations]: - list-files List eligible files in data path. Shortcut 'lsf' - cache-clear Delete all cached keys. Shortcut 'cc' - help Display help - rm-file Remove files. Shortcut 'rmf' -[File Operations]: - ls [path] List contents at given path - tree List all contents - create Create a file or change key - get Get values of targets - copy Copy the target value to clipboard. Shortcut 'x' - set Set the value of target - add Prompt for input value on paths - new Generate a random password at target - rm Delete targets - mv Move targets - exec Execute the following command inside the archive. - cached Returns wether or not a key is currently cached. Shortcut 'ch' - rm-cache Delete the cached key for this file. Shortcut 'rmc' - -[Config]: - *Variable* *Default value* *Description* - ---------------------------------------------------------------------------- - CONFIGFILE '\$XDG_CONFIG_HOME/zpass/defaut.conf' Path to the config file to load - ZPASS_PATH '\$XDG_DATA_HOME/zpass' Folder containing password files - ZPASS_CACHE_PATH '\$XDG_CACHE_HOME/zpass' Path used for caching keys - ZPASS_FILE 'default' File to use for operations - ZPASS_KEY Key to use for encrypting/decrypting files - ZPASS_KEY_CACHE_TIME '60' Time a key stays in cache for decrypting, in seconds - ZPASS_CLIPBOARD_TIME '30' Time until clipboard gets cleared after copy, in seconds - ZPASS_UNK_OP_CALL 'copy' Operation to call on unrecognized first argument - ZPASS_RAND_LEN Length of random passwords generated by 'new' - ZPASS_REMOTE_ADDR SSH server the file is on - ZPASS_REMOTE_PORT '22' SSH server port - ZPASS_SSH_ID SSH private key to use - -All operations can be shortened to their first char unless specified -Unknown first argument will perform the operation described in 'ZPASS_UNK_OP_CALL' on that argument -" -} diff --git a/zpass/src/main.sh b/zpass/src/main.sh deleted file mode 100644 index 2319a90..0000000 --- a/zpass/src/main.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/lxsh - -%include util.sh config.sh *.sh - -## pre exec - -clean_cache 2>/dev/null -[ $# -lt 1 ] && usage && return 1 - -arg=$1 -shift 1 - -## exec - -case $arg in - -h|h|help) usage && exit 1;; - lsf|list-files) list_files ;; - rmf|rm-file) remove_files "$@" ;; - cc|cache-clear) clear_cache 2>/dev/null ;; - ch|cached) get_key_cached >/dev/null 2>&1 ;; - rmc|rm-cache) delete_cache 0 >/dev/null 2>&1 ;; - c|create) create ;; - t|tree) _tree "$@" ;; - s|set) _set "$@" ;; - a|add) add "$@" ;; - n|new) new "$@" ;; - g|get) get "$@" ;; - x|copy) copy "$1" ;; - e|exec) archive_exec "$@" ;; - l|ls|list) sanitize_paths "$@" && __NOPACK=y archive_exec ls -Apw1 -- "$@" ;; - r|rm) sanitize_paths "$@" && archive_exec rm -rf -- "$@" ;; - m|mv) sanitize_paths "$@" && archive_exec mv -f -- "$@" ;; - *) [ -n "$ZPASS_UNK_OP_CALL" ] && "$0" $ZPASS_UNK_OP_CALL "$arg" "$@" ;; -esac diff --git a/zpass/src/operation.sh b/zpass/src/operation.sh deleted file mode 100644 index 3aec44e..0000000 --- a/zpass/src/operation.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/sh - -# $@ = paths -_tree() -{ - if [ $# -gt 0 ] - then - fulltree=$(decrypt | tar -tf - 2>/dev/null) || exit $?; - - for N - do - [ $# -gt 1 ] && echo "> $N:" - echo "$fulltree" | grep "^$(escape_chars "$N")" | sed "s|^$N||g ; "' s|^/||g ; /\/$/d ; /^$/d' - done - - else - { decrypt | tar -tf - 2>/dev/null || exit $?; } | sed '/\/$/d ; /^$/d' - fi -} - -# $@ = paths -get() -{ - [ $# -lt 1 ] && return 1 - __NOPACK=y archive_exec sh -c ' - for N - do - ( - cat "$N" 2>/dev/null && exit 0 - [ -d "$1" ] && cat "$N/default" 2>/dev/null && exit 0 - exit 1 - ) || { echo "$N: not found" >&2 && exit 1; } - done - ' sh "$@" -} - -# $1 = path -copy() -{ - copy_check || return $? - { get "$1" || return $?; } | remove_trailing_newline | clipboard && clipboard_clear "$ZPASS_CLIPBOARD_TIME" -} - -# $@ = path -new() -{ - [ $# -lt 1 ] && return 1 - archive_exec sh -c " - for N - do - mkdir -p \"\$(dirname \"\$N\")\" || exit \$? - { tr -cd 'a-zA-Z0-9!-.' < /dev/urandom | head -c $ZPASS_RAND_LEN && echo; } > \"\$N\" || exit \$? - done - " sh "$@" -} - -# $1 = path , $@ = value -_set() -{ - [ $# -lt 1 ] && return 1 - ref=$1 - shift 1 - archive_exec sh -c "mkdir -p '$(dirname "$ref")' && printf '%s\n' '$*' > '$ref'" -} - -add() -{ - [ $# -lt 1 ] && return 1 - archive_exec true # prompt for the key - for N - do - val=$(prompt_password "New value for $N") || return $? - _set "$N" "$val" || return $? - done -} diff --git a/zpass/src/prompt.sh b/zpass/src/prompt.sh deleted file mode 100644 index c466af2..0000000 --- a/zpass/src/prompt.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh - -# $1 = prompt -console_prompt_hidden() -{ - ( - _tty_on() { stty echo; } - trap _tty_on INT - local prompt - printf "%s" "$1" >&2 - stty -echo - read -r prompt || { stty echo; return 1; } - stty echo - printf "\n" >&2 - echo "$prompt" - ) -} - -# $1 = prompt message -prompt_password() { - if [ -n "$DISPLAY" ] - then - if which kdialog >/dev/null 2>&2 - then kdialog --title "$fname" --password "$1" 2>/dev/null - else zenity --title "$fname" --password 2>/dev/null - fi - else - console_prompt_hidden "$1: " - fi -} - -# $1 = message -error_dialog() { - if which kdialog >/dev/null 2>&2 - then kdialog --title "$fname" --error "$1" 2>/dev/null - else zenity --title "$fname" --error --text="$1" 2>/dev/null - fi -} - -new_key_with_confirm() -{ - [ -n "$ZPASS_KEY" ] && echo "$ZPASS_KEY" && return 0 - pass1=1 - pass2=2 - while [ "$pass1" != "$pass2" ] - do - pass1=$(prompt_password "Enter new key") || error 100 "Cancelled" - pass2=$(prompt_password "Confirm key") || error 100 "Cancelled" - [ "$pass1" != "$pass2" ] && error_dialog "Passwords do not match.\nTry again" - done - write_cache "$pass1" & - echo "$pass1" -} - -# $1 = prompt message -ask_key() { - message="Enter key" - [ -n "$1" ] && message="$1" - key=$(prompt_password "$message") || return $? - write_cache "$key" & - echo "$key" -} diff --git a/zpass/src/util.sh b/zpass/src/util.sh deleted file mode 100644 index b1cbf40..0000000 --- a/zpass/src/util.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh - -error(){ - ret=$1 && shift 1 && echo "$*" >&2 && exit $ret -} - -randalnum() { - tr -cd '[a-zA-Z]' < /dev/urandom | head -c $1 -} - -# $* = input -escape_chars() { - echo "$*" | sed 's|\.|\\\.|g;s|/|\\/|g' -} - -remove_trailing_newline() { - awk 'NR>1{print PREV} {PREV=$0} END{printf("%s",$0)}' -} - -# $@ = paths -sanitize_paths() -{ - for N - do - echo "$N" | grep -q "^/" && echo "Path cannot start with /" >&2 && return 1 - echo "$N" | grep -qw ".." && echo "Path cannot contain .." >&2 && return 1 - done - return 0 -} - -# $1 = file -getpath() { - if [ -n "$ZPASS_REMOTE_ADDR" ] - then echo "$ZPASS_REMOTE_PORT:$ZPASS_REMOTE_ADDR:$file" - else readlink -f "$file" - fi -} - -# $1 = file -filehash(){ - getpath "$file" | md5sum | cut -d' ' -f1 -} - -keyfile(){ - printf "%s.key" "$(filehash)" -} - -_cmd_() { - if [ -n "$ZPASS_REMOTE_ADDR" ] - then - if [ -n "$ZPASS_SSH_ID" ] - then - ssh -i "$ZPASS_SSH_ID" "$ZPASS_REMOTE_ADDR" "$@" || return $? - else - ssh "$ZPASS_REMOTE_ADDR" "$@" || return $? - fi - else - sh -c "$*" - fi -}