In Zsh I use the following global alias:
alias -g L='| less --chop-long-lines'
When executing echo "hello world" L in Zsh, less will display the sentence 'hello world'.
How to write a fish function equivalent to a Zsh global alias?
Zsh's global alias feature is unique to zsh.
fish cannot recognize aliases except where you'd expect a command, as the first word.
Related
I have a bash script and I want to use a command in it, that I defined in my config.fish like this:
alias setbg='feh --bg-fill'
However when I use the command in my bash script, I get:
setbg: command not found
How do I make fish aliases visible to bash scripts?
You don't.
Fish aliases are internal to fish only, and since bash and fish are incompatible it's not guaranteed you can source them either.
However, fish doesn't actually have aliases, the alias command is just a wrapper around defining functions, and unlike bash fish always reads its configuration.
So you can run fish -c 'setbg'.
Alternatively you could make a file with aliases that works in both bash and fish. As long as you stick to the common subset like simple alias key='value' that would work, but you couldn't use any incompatible expressions like even if.
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!
This question already has answers here:
using alias in shell script? [duplicate]
(7 answers)
Closed 2 years ago.
Definin an alias on Linux system is very simple.
From the following example we see that: the I_am_only_ls_alias alias command gives us the output as ls command
# alias I_am_only_ls_alias=ls
# I_am_only_ls_alias
Output:
file file1
But when I trying to do the same in bash script (define alias I_am_only_ls_alias), I get I_am_only_ls_alias: command not found.
Example of my bash script:
alias_test.bash
#!/bin/bash
alias I_am_only_ls_alias=ls
I_am_only_ls_alias
Run the bash script - alias_test.bash
/tmp/alias_test.bash
Output:
/tmp/: line 88: I_am_only_ls_alias: command not found
So, first I want to ask:
Why doesn't bash recognize the command I_am_only_ls_alias as an alias?
And what do I need to do in order to define aliases inside a bash script? Is it possible?
From the bash man page:
Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt (see the
description of shopt under SHELL BUILTIN COMMANDS below).
So this should work:
#!/bin/bash
shopt -s expand_aliases
alias I_am_only_ls_alias=ls
I_am_only_ls_alias
Scripts usually use functions, not aliases.
Barmar's answer is the correct one for including an alias, but it's likely that you'll actually find a Bash function to be more flexible/useful.
For example this is materially the same as the alias version, but can be expanded much more easily:
timp#helez:~/tmp$ cat test.sh
#!/usr/bin/bash
function i_am_only_an_ls_func {
ls "$#"
}
i_am_only_an_ls_func
timp#helez:~/tmp$ ./test.sh
0600871h.html
[snip]
timp#helez:~/tmp$
The $# is irrelavent in this example, but it means that anything after i_am_only_an_ls_func will be added after the ls command, since $#, $1, $2, etc contain the arguments to the function, much the same as for a normal script. (Note that $0 is still the name of the parent script not the function)
Aliases cannot be defined in shell script that you execute - their effect will be gone once shell process finished execution.
You can, however, define aliases in your ~/.bashrc or in separate shell script that you source from (but not execute!). In that case, aliases are imported into already running shell process, and thus survive and actually work as you would expect.
I am pretty new to bash, and I want to include an env for bash aliases.. I want to do something like the following
alias foo="bar $(baz)"
So that I could do something like the following
> baz=40
> foo
and foo will expand to the command bar 40. Currently the above does not work because $(baz) is expanded while making the alias. Do I have to wrap this inside a function or something?
You need to use single quotes (') to prevent bash from expanding the variable when creating the alias:
$ alias foo='echo "$bar"'
$ bar="hello"
$ foo
hello
Aliases don't have an "environment". An alias is simply a "dumb" text substitution. In the question, an environment variable isn't being used - only a shell variable. If you want to use the environment, use a function. In this case, there is no advantage to an alias over a function.
$ alias foo='echo "$bar"'
$ bar=hi foo
This produces no output because the environment set for a simple command doesn't apply to expansions.
$ alias foo=$'eval \'echo "$bar"\''
$ bar=hi foo
hi
If a function were used instead, there wouldn't be a problem.
$ foo() { echo "$bar"; }
$ bar=hi foo
hi
When in doubt, always use a function.
Edit
Technically, the above is bash-only. Doing this in a fully portable way is nearly impossible.
In dash, mksh, bash POSIX mode, and other POSIX shells you can do:
foo() { echo "$bar"; }
bar=hi command eval foo
However, this won't work in ksh93 or zsh. (I've already reported a bug for ksh93 but it may never be fixed.) In mksh and ksh93 you should instead define functions using the function keyword, but that isn't POSIX. I'm not aware of any solution that will work everywhere.
To make matters worse, extra exceptions are being added to POSIX 2008-TC1 so that the way environment assignments work will be even more complicated. I suggest not using them unless you really know what you're doing.
I do the following to delay expansion of environment variables in aliases until they are run,
alias foo="ls \${FOO_DIR}"
for example to show the contents of the dynamically-defined value of FOO_DIR.
Why doesn't the following work?
$ alias sayHello='/bin/echo "Hello world!"'
$ sayHello
Hello world!
$ nohup sayHello
nohup: appending output to `nohup.out'
nohup: cannot run command `sayHello': No such file or directory
(the reason I ask this question is because I've aliased my perl and python to different perl/python binaries which were optimized for my own purposes; however, nohup gives me troubles if I don't supply full path to my perl/python binaries)
Because the shell doesn't pass aliases on to child processes (except when you use $() or ``).
$ alias sayHello='/bin/echo "Hello world!"'
Now an alias is known in this shell process, which is fine but only works in this one shell process.
$ sayHello
Hello world!
Since you said "sayHello" in the same shell it worked.
$ nohup sayHello
Here, a program "nohup" is being started as a child process. Therefore, it will not receive the aliases.
Then it starts the child process "sayHello" - which isn't found.
For your specific problem, it's best to make the new "perl" and "python" look like the normal ones as much as possible. I'd suggest to set the search path.
In your ~/.bash_profile add
export PATH="/my/shiny/interpreters/bin:${PATH}"
Then re-login.
Since this is an environment variable, it will be passed to all the child processes, be they shells or not - it should now work very often.
For bash: Try doing nohup 'your_alias'. It works for me. I don't know why back quote is not shown. Put your alias within back quotes.
With bash, you can invoke a subshell interactively using the -i option. This will source your .bashrc as well as enable the expand_aliases shell option. Granted, this will only work if your alias is defined in your .bashrc which is the convention.
Bash manpage:
If the -i option is present, the shell is interactive.
expand_aliases: If set, aliases are expanded as described above under ALIASES. This option is enabled by default for interactive shells.
When an interactive shell that is not a login shell is started, bash reads and executes commands from /etc/bash.bashrc and ~/.bashrc, if these files exist.
$ nohup bash -ci 'sayHello'
If you look at the Aliases section of the Bash manual, it says
The first word of each simple command, if unquoted, is checked to see
if it has an alias.
Unfortunately, it doesn't seem like bash has anything like zsh's global aliases, which are expanded in any position.