I have few bash functions like
#!/bin/sh
git-ci() {
...
}
When I was not using fish I had a source ~/.my_functions line in my ~/.bash_profile but now it doesn't work.
Can I use my bash functions with fish? Or the only way is to translate them into fish ones and then save them via funcsave xxx?
As #Barmer said fish doesn't care about compatibility because one of its goals is
Sane Scripting
fish is fully scriptable, and its syntax is simple, clean, and consistent. You'll never write esac again.
The fish folks think bash is insane and I personally agree.
One thing you can do is to have your bash functions in separate files and call them as functions from within fish.
Example:
Before
#!/bin/bash
git-ci() {
...
}
some_other_function() {
...
}
After
#!/bin/bash
# file: git-ci
# Content of git-ci function here
#!/bin/bash
# file: some_other_function
# Content of some_other_function function here
Then put your script files somewhere in your path. Now you can call them from fish.
Hope that helps.
The syntax for defining functions in fish is very different from POSIX shell and bash.
The POSIX function:
hi () {
echo hello
}
is translated to:
function hi
echo hello
end
There are other differences in scripting syntax. See the section titled Blocks in Fish - The friendly interactive shell for examples.
So it's basically not possible to try to use functions that were written for bash in fish, they're as different as bash and csh. You'll have to go through all your functions and convert them to fish syntax.
If you don't want to change all the syntax, one workaround is to simply create a fish function that runs a bash script and passes the arguments right along.
Example
If you have a function like this
sayhi () {
echo Hello, $1!
}
you'd just change it by stripping away the function part, and save it as an executable script
echo Hello, $1!
and then create a fish function which calls that script (with the name sayhi.fish, for example)
function sayhi
# run bash script and pass on all arguments
/bin/bash absolute/path/to/bash/script $argv
end
and, voila, just run it as you usually would
> sayhi ivkremer
Hello, ivkremer!
Related
I have a function defined in my .zshenv like this:
function my_func() {
echo $1
}
I then execute a bash script from the zsh which its content is:
type my_func
I got an error: /tmp/test.bash: line 3: type: my_func: not found
While if I type type my_func from the zsh I got: my_func is a shell function from
Is there a way to use zsh defined function in a bash script? It seems to work for the exported variables
How bash does it
Bash itself can export its functions to other bash shells. It does so by exporting a string environmental variable of the form:
BASH_FUNC_functionNameHere%%=() { functionBodyHere; }
So in theory you could use the following zsh-command to export your function for bash:
export "BASH_FUNC_my_func%%=() { $(echo; typeset -f my_func | tail -n+2) }"
However, this does not work because zsh doesn't allow %% in identifiers.
Workaround
Depending on how you start bash, you might be able to inject the function definition into the bash process.
When running a bash script like bash myScript or ./myScript you can use bash -c "$(typeset -f my_func); export -f my_func; myScript" instead.
When starting an interactive bash shell using bash, you can use bash -c "$(typeset -f my_func); export -f my_func; exec bash" instead.
The right way
Either way, your function has to be a polyglot. That is, the source code of the function has to be understood by both zsh and bash. Above approach is not really viable if you want to export many functions or want to call many bash scripts.
It would be easier to define each of your functions inside its own script file and add the locations of those scripts to $PATH. That way you can call your "functions" from every shell and they will always work independently from your current shell.
Replacing the functions by script files only works if your functions don't want to modify the parent shell. cd or setting variables has no effect on the caller. If you want to do stuff like this, you can still use a script file, but then have to source it using . myFunctionFile. For sourcing, the source code has to be a polyglot again.
A script like the following:
#!/bin/bash
function hello {
echo "Hello World"
}
hello
will work fine but when I call it with nohup
nohup ./myScript.sh
the script no longer works and the following is printed:
./myScript.sh: 5: ./myScript.sh: function: not found
Hello World
./myScript.sh: 9: ./myScript.sh: Syntax error: "}" unexpected
I know that there is no point in using nohup for this script since it runs fairly quick but I have another script that is going to take several hours to run and I have used that function syntax in it. Is there a way to fix this?
Note that to declare a function in POSIX standard shell, you just write the function name followed by a pair of empty parentheses, and a body in curly brackets:
#!/bin/bash
hello() {
echo "Hello World"
}
hello
Some shells, like bash, also accept the function keyword to declare functions, but based on your error message, it looks like the shell that you are using does not accept it. For portability, it would be best to use the POSIX standard declaration style.
The reason you see the difference between running the script directly and running the script under nohup is the blank lines at the beginning of the file. The #! need to be the first two characters of the file in order to specify the interpreter, otherwise that is just a comment. It looks like when executed from within a Bash shell, the script gets interpreted by Bash and it recognizes the Bash extension. But when run from nohup, it gets interpreted by sh, which on some systems is a more bare-bones shell like dash that only supports the POSIX syntax above.
I tried 3 internet examples to write a bashe shell function and call it via my xterm terminal with no success.
1-my functions are saved in a file "example" and this file is inexecutable mode.
2-inside this example file i wrote:
#!/bin/bash
function quit {
exit
}
function hello {
echo Hello!
}
3- in xterm terminal, in the folder that this file is located i called these two functions in these ways:
$./quit $./hello
and in this way:
$quit $hello
none of them work.but if i change the following function to a script (without function word) and call the FILE, it works.
Any idea, what is going on?
Thanks
You need to source your script to load function definitions to current shell environment:
# source script
. example
# call function
hello
# call function
quit
You need to make the function definitions available to the outside shell. For this, you need to source the example file:
. example
quit
hello
You can also do source example.
Once you've written the functions, they only visible inside the script file itself. For them to be visible outside it, you need to tell the script to export the functions to the environment.
Try adding export -f quit and export -f hello after your function definitions.
Let's clear up confusion with the ./ and $ operators.
The first operator ./ is used when you want to call a script in the current directory. For example, if you've defined your script in some file script.sh, then you could call it with ./script.sh (make sure you have execute permissions - you can add them with chmod +x script.sh).
The second operator $ is used to look at environment variables. These are variables which are defined by default in the bash shell, or variables which you have defined and exported to the shell. Try entering the following into your shell.
pi=3.14
echo $pi
3.14
Here, the $ prefix allows you to access the variable you created.
./quit Or ./hello means that you have files named quit and hello and you want to execute them.
and $quit and $hello means that quit and hello are predefined commands (executable files in $PATH folders e.g /usr/bin)
when you define a function in shell file, you should use it in that file too!
Consider this script I wrote, which should go into parent directory, when no argument is given (the if ... part).
#/bin/bash
if (($# == 0))
then
cd ..
else
for basename
do
cd ${PWD%$basename*}$basename
done
fi
The problem is, that if I execute it like this
./up.sh
the cd is executed in a subshell, rendering it useless.
If I execute the script using source, it works, but I don't want to call it that way (I makes calling the script to complicated, also you would expect to call it directly if found in the PATH).
An arbitrary program (such as your bash program) cannot change the working directory of the parent process, as that would pretty much break all existing processes that spawn children.
You should define a bash alias or function instead. As you have discovered, typing source ./up.sh (or shorter: . ./up.sh) works too.
I suggest using a function instead of a script
function myscript()
{
// use $1, $2, "$#" as usual in scripts
local v1="bla" # can use globals
export PATH="$PATH" # but global shell env too
somedirectory=..
cd $somedirectory
}
Alternatively, alias would work (but it doesn't support redirection, argument passing, flow control etc well, and you cannot nest them in $() IIRC).
Lastly source the existing script in the current shell like so:
source ./script.sh
ksh and bash have shorthands for that:
. ./script.sh
Beware of scripts with 'exit' statements though: they will exit the parent shell!
I have a simple shell script as follows:
myfunc()
{
#print hello world
echo "Hello World";
}
myfunc
The script works fine when I execute in linux pc but when I run the same in uclinux, I get the error as "syntax error".
What could be reason for the problem?
Update:
The following code works in uclinux:
####\#!/bin/sh
echo "Hello World"
But, the following code is not working:
####!/bin/sh
myfunc()
{
#print hello world
echo "Hello World";
}
myfunc
The result depends what shell you run. Most uclinux's shells are actually symbolic links to Busybox. Busybox implements various tiny shells for different memory foot print requirements. As I remember, only ash supports function syntax. Check your busybox version and its build config.
Maybe your installation of uclinux uses a different shell?
Saying "shell script doesn't work" is like saying "my source code doesn't work". Of course the phrase only makes sense if you say what language your source code is in. Similarly for shell script: is it bash? is it ksh? is it tcsh? For uclinux I highly suspect it's busybox.
Your shell script should have a shebang line that will cause the script to be executed by the shell you designate. This can reduce or eliminate many unexpected errors due to differences in syntax between shells that are caused when the script is executed by the current (or default) shell which may be different for a number of reasons.
The first line of the script file should be similar to:
#!/bin/sh
with the path and name of the shell appropriate to your needs.
Is your actual myfunc defined in one line as you show it? That's a syntax error since you're commenting out lots of stuff including the }.
If you put myfunc() { #print hello world echo "Hello World"; } on one line, then
#print hello world echo "Hello World"; } gets interpreted as comment. Remove the part #print hello world and try again.
if using Busybox and hush
Configure Your BusyBox Shell Part To suppot Function:
make busyBox-menuconfig
Shells -> Support Function .... (Should be checked )