fish shell: unable to erase function - prompt

When trying to temporarily disable a fish_mode_prompt function:
function get_input -a prompt var_name -d 'get user input and place it in var_name'
functions -c fish_mode_prompt fish_mode_prompt_tmp
functions -e fish_mode_prompt
read --global --prompt-str="$prompt" $var_name
functions -c fish_mode_prompt_tmp fish_mode_prompt
functions -e fish_mode_prompt_tmp
end
I get the following error:
functions: Function “fish_mode_prompt” already exists. Cannot create copy “fish_mode_prompt_tmp”
~/.config/fishdots/plugins/fishdots_crm/init/rc1.d/01.functions.fish (line 114):
functions -c fish_mode_prompt_tmp fish_mode_prompt
^
in function “get_input”
called on standard input
with parameter list “hello world: charlie”
functionsfunctions - print or erase functions
-
Synopsis
functions [ -a | --all ] [ -n | --names ]
functions [ -D | --details ] [ -v ] FUNCTION
functions -c OLDNAME NEWNAME
functions -d DESCRIPTION FUNCTION
functions [ -e | -q ] FUNCTIONS...
functions: Type “help functions” for related documentation
I'm not entirely sure what's happening here. Should this work?

See https://github.com/fish-shell/fish-shell/issues/741. functions --erase does not actually remove the file containing the autoloaded function definition.
Rather than attempt to rename the function in that fashion just replace it with a dummy implementation:
function fish_mode_prompt; end
read --global --prompt-str="$prompt" $var_name
function -e fish_mode_prompt
But I don't understand why you would want to do this. If you're using vi mode you really should just let its state indicator be present at all times. Even when executing a read command. If you dislike the state indicator I would simply define your own ~/.config/fish/functions/fish_mode_prompt.fish autoloaded script with an empty fish_mode_prompt function.

Related

Access positional parameters from within a function in Bash

In a bash script file, is there a way that I can use command line arguments from within a function which has parameters?
Or do I need to assign all command line parameters to a variable for them to be accessible in the function body?
echo $1 # may be "abc"
function f() { $1; } # will be "def", but I need "abc" here
f "def"
PS: I found a similar question on stack overflow, but that question doesn't deal with the issue I describe here?
Just for the record, this is possible in extdebug mode through BASH_ARGC and BASH_ARGV variables, but populating a global array with positional parameters is much easier than that, and has no side-effects.
$ bash -O extdebug -s foo bar
$ f() {
> declare -p BASH_ARGC BASH_ARGV
> echo ${BASH_ARGV[BASH_ARGC[0] + BASH_ARGC[1] - 1]}
> }
$ f 42 69
declare -a BASH_ARGC=([0]="2" [1]="2")
declare -a BASH_ARGV=([0]="69" [1]="42" [2]="bar" [3]="foo")
foo
SCRIPT_ARG=$1
function f() {
FUNC_ARG=$1;
echo $SCRIPT_ARG # Prints "abc"
echo $FUNC_ARG # Prints "def"
}
f "def"

Pipe username and other parameters to command-line utility

Having some command-line utility that asks for input several times when you launch it, e.g. here I need to pass username and host to some command.
And I would like to make other command so it will pass these args
user:~$ run_something
username:
host:
How it is possible to pipe these parameters sequentially to command, e.g.:
user:~$ echo "my_user, my_host" | run_something
use xargs
eg.
echo "mydir" | xargs ls
Will list the files in the directory mydir
One way to do this is by using read from standard input:
run_something() {
read -r username host && declare -p username host;
}
then run it as:
echo "my_user my_host" | run_something
to get output:
declare -- username="my_user"
declare -- host="my_host"
Another way is to set variables directly before calling function:
run_something() {
declare -p username host
}
then run it as:
username='my_user' host='my_host' run_something
to get the same output:
declare -x username="my_user"
declare -x host="my_host"
You need to send the newlines that you would otherwise type after each line. run_something is expecting two lines of input:
printf '%s\n' "username" "host" | run_something

Return an array from shell script to iterate/process in shell command line

I have a script that makes a list of calls to APIs and collects the response Codes into an array called updateResponses. I looked many placed and declare -p was recommended, but it's not working the way it's described or maybe I am using it wrong.
What I need : return the Array from the script and verify the elements by iterating over them.
My script.sh contains the highlights for this action:
updateResponses=()
do
..get statusCodes from list of calls in a loop...
updateResponses+=("$statusCode")
done
declare -p updateResponses
in my terminal after I execute this script, I see the array printed out but it is not an array to iterate over although it looks as if it was re-initialized to be used. Running echo "${#updateResponses[#]}" returns 0 as the size.
Example of the output after script.sh is done running :
declare -a updateResponses='([0]="200" [1]="200" [2]="200" [3]="200" [4]="200" [5]="200" [6]="200" [7]="200" [8]="200" [9]="200" [10]="200" [11]="200" [12]="200" [13]="200" [14]="200" [15]="200" [16]="200" [17]="200" [18]="200" [19]="200" [20]="200" [21]="200" [22]="200" [23]="200" [24]="200" [25]="200" [26]="200" [27]="200" [28]="200" [29]="200" [30]="200" [31]="200" [32]="200" [33]="200")'
You need to run the output of the script in the context of the current shell, e.g.
$ . <(arr=('a b' 'c d' 'e;f') ; declare -p arr)
$ echo ${arr[1]}
c d

Get a list of function names in a shell script [duplicate]

This question already has answers here:
How do I list the functions defined in my shell? [duplicate]
(8 answers)
Closed 4 years ago.
I have a Bourne Shell script that has several functions in it, and allows to be called in the following way:
my.sh <func_name> <param1> <param2>
Inside, func_name() will be called with param1 and param2.
I want to create a help function that would just list all available functions, even without parameters.
The question: how do I get a list of all function names in a script from inside the script?
I'd like to avoid having to parse it and look for function patterns. Too easy to get wrong.
Update: the code. Wanted my help() function be like main() - a function added to the code is added to the help automatically.
#!/bin/sh
# must work with "set -e"
foo ()
{
echo foo: -$1-$2-$3-
return 0
}
# only runs if there are parameters
# exits
main ()
{
local cmd="$1"
shift
local rc=0
$cmd "$#" || rc=$?
exit $rc
}
if [[ "$*" ]]
then
main "$#"
die "how did we get here?"
fi
You can get a list of functions in your script by using the grep command on your own script. In order for this approach to work, you will need to structure your functions a certain way so grep can find them. Here is a sample:
$ cat my.sh
#!/bin/sh
function func1() # Short description
{
echo func1 parameters: $1 $2
}
function func2() # Short description
{
echo func2 parameters: $1 $2
}
function help() # Show a list of functions
{
grep "^function" $0
}
if [ "_$1" = "_" ]; then
help
else
"$#"
fi
Here is an interactive demo:
$ my.sh
function func1() # Short description
function func2() # Short description
function help() # Show a list of functions
$ my.sh help
function func1() # Short description
function func2() # Short description
function help() # Show a list of functions
$ my.sh func1 a b
func1 parameters: a b
$ my.sh func2 x y
func2 parameters: x y
If you have "private" function that you don't want to show up in the help, then omit the "function" part:
my_private_function()
{
# Do something
}
typeset -f returns the functions with their bodies, so a simple awk script is used to pluck out the function names
f1 () { :; }
f2 () { :; }
f3 () { :; }
f4 () { :; }
help () {
echo "functions available:"
typeset -f | awk '/ \(\) $/ && !/^main / {print $1}'
}
main () { help; }
main
This script outputs:
functions available:
f1
f2
f3
f4
help
You call this function with no
arguments and it spits out a
"whitespace" separated list of
function names only.
function script.functions () {
local fncs=`declare -F -p | cut -d " " -f 3`; # Get function list
echo $fncs; # not quoted here to create shell "argument list" of funcs.
}
To load the functions into an array:
declare MyVar=($(script.functions));
Of course, common sense dictates that
any functions that haven't been
sourced into the current file before
this is called will not show up in the
list.
To Make the list read-only and
available for export to other scripts
called by this script:
declare -rx MyVar=($(script.functions));
To print the entire list as newline
separated:
printf "%s\n" "${MyVar[#]}";
The best thing to do is make an array (you are using bash) that contains functions that you want to advertise and have your help function iterate over and print them.
Calling set alone will produce the functions, but in their entirety. You'd still have to parse that looking for things ending in () to get the proverbial symbols.
Its also probably saner to use something like getopt to turn --function-name into function_name with arguments. But, well, sane is relative and you have not posted code :)
Your other option is to create a loadable for bash (a fork of set) that accomplishes this. Honestly, I'd prefer going with parsing before writing a loadable for this task.

ksh: assigning function output to an array

Why doesn't this work???
#!/bin/ksh
# array testfunc()
function testfunc {
typeset -A env
env=( one="motherload" )
print -r $env
return 0
}
testfunc # returns: ( one=motherload )
typeset -A testvar # segfaults on linux, memfaults on solaris
testvar=$(testfunc) # segfaults on linux, memfaults on solaris
print ${testvar.one}
note: I updated the above script to print ${testvar.one} from print $testvar to show more precisely what I am trying to accomplish.
I am sure this has been asked before, but I am not sure what to search on and everything I have been trying to use for keywords is not bringing me any answers that relate to my problem.
ksh version:
linux: version sh (AT&T Research) 1993-12-28 s+
solaris: version sh (AT&T Research) 93s+ 2008-01-31
Update:
So another question is, this will run in ksh 93t+ without giving an error, but, it doesn't assign the array properly. I would I go about assigning an array from a function? I tried assigning the array like this also:
typeset -A testvar=$(testfunc)
print ${testvar.one}
But that also didn't work properly.
EDIT
So what is happening here?
typeset -A env=( one="motherload" two="vain" )
print ${env.one}
print ${env.two}
I thought this was how you defined associative arrays, maybe what I was looking at was old but who knows.... seems odd behaviour since this prints out "motherload" and "vain"
Your script works fine for me on Linux with ksh 93t+.
Since it's the same script and you're getting similar errors in two different environments, I would suspect stray characters in the file. Try one of these to show any stray characters that might be present:
hd filename
cat -v filename
hexdump -C filename
If it's simply a matter of DOS line endings, then this will fix that:
dos2unix filename
Edit:
Here's one way to create and populate an associative array in ksh:
$ typeset -A testvar
$ testvar=([one]="motherlode" [two]="vein" [waste]="tailings")
$ echo ${testvar[two]}
vein
$ testvar[ore]="gold"
$ echo ${!testvar[#]} # print the indices of the array
one two waste ore
$ typeset -p testvar # show the current definition of the array
typeset -A testvar=([one]="motherlode" [two]="vein" [waste]="tailings" [ore]="gold")
As you can see, ksh uses bracketed subscripts for arrays. Dotted notation is used for accessing members of a compound variable.
I don't believe ksh functions can return arrays. However, you can use the print technique you have in your function (but add square brackets around the index name) and use eval to do the assignment.
$ typeset -A testvar
$ eval "testvar=($(testfunc))"
or to append to an existing array:
$ eval "testvar+=($(testfunc))"
Unless your function is using associative arrays internally, you don't necessarily need to use them to build your output.
However, if you do, you can parse from the result of typeset -p:
$ result=$(typeset -p env)
$ result=${result#*\(}
$ result=${result%\)*}
$ print result
or iterate through the array:
$ for index in ${!env[#]}; do print -n "[$index]=${env[$index]} "; done; print
You may want to consult the documentation concerning discipline functions and type variables
Here is an alternative to getting any return value from a function using name reference. The value returned will be stored in a variable defined as the first positional argument of the function (not declaring the variable beforehand will work but the variable will be global):
#################################
# Example using compound variable
#################################
function returnCompound {
typeset -n returnVal="$1"
returnVal=( one="motherloadCompound" )
return 0
}
# Declaring the variable to keep it in this scope
# Useful for calling nested functions whitout messing
# with the global scope
typeset myNewCompoundVar
returnCompound myNewCompoundVar
echo "Compound: ${myNewCompoundVar.one}"
##################################
# Example using asssociative array
##################################
function returnMap {
typeset -n myNewMapVar="$1"
myNewMapVar=( [one]="motherloadMap" )
typeset nestedCompoundVar
returnCompound nestedCompoundVar
echo "Compound (Nested) from inside: ${nestedCompoundVar.one}"
return 0
}
# Declaring the variable to keep it in this scope
# Useful for calling nested functions whitout messing
# with the global scope
typeset myNewMapVar
returnMap myNewMapVar
echo "Associative array: ${myNewMapVar[one]}"
echo "Compound (Nested) from outside: ${nestedCompoundVar.one}"
Output:
Compound: motherloadCompound
Compound (Nested) from inside: motherloadCompound
Associative array: motherloadMap
Compound (Nested) from outside:
Important side notes:
Function declarations must be done using the function keyword or else the concept of local scope variable won't be taken under account. In which case the name of your reference variable and global variable might clash if they happen to be the same, resulting in a typeset: invalid self reference error. This can be tested by changing the declaration of the 'returnMap' function.
If you do not declare the return variable before the function call, the variable to which is assigned the return value will be created globally and not limited to the calling scope.

Resources