How to get name of alias that invoked bash script - bash

$0 expands to the name of the shell script.
$ cat ./sample-script
#!/bin/bash
echo $0
$ chmod 700 ./sample-script
$ ./sample-script
./sample-script
If the shell script is invoked via a symbolic link, $0 expands to its name:
$ ln -s ./sample-script symlinked-script
$ ./symlinked-script
./symlinked-script
How could I get the name of an alias? Here `$0' expands again to the filename:
$ alias aliased-script=./sample-script
$ aliased-script
./sample-script

Aliases are pretty dumb, according to the man page
...Aliases are expanded when a command is read, not when it is executed...
so since bash is basically just replacing a string with another string and then executing it, there's no way for the command to know what was expanded in the alias.

I imagine you already know this, but for the record the answer is: you need cooperation by the code implementing the alias.
alternate_name () {
MY_ALIAS_WAS=alternate_name real_name "$#"
}
or, if you really want to use the superseded alias syntax:
alias alternate_name="MY_ALIAS_WAS=alternate_name real_name"
...and then...
$ cat ~/bin/real_name
#!/bin/sh
echo $0, I was $MY_ALIAS_WAS, "$#"

bash does not make this available. This is why symlinks are used to invoke multiplex commands, and not aliases.

Related

why alias won't change directory with ls -latr? [duplicate]

This question already has answers here:
Make a Bash alias that takes a parameter?
(24 answers)
Closed last month.
I'm very interested in why this works this way and if we find a solution that's just a benefit of asking the question.
Using kshell,bash and observed the same results. Below is from GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu).
Below is from terminal.
alias tryme='tb=$1;cd $tb'
pwd
/home/tbink1
tryme /home/tbink1/Documents
pwd
/home/tbink1/Documents
But using below doesn't switch directories.
alias tryme='tb=$1;cd $tb;ls -latr'
pwd
/home/tbink1/Documents
tryme /home/tbink1/Pictures
<file list from /home/tbink1/Pictures>
pwd
/home/tbink1/Documents
Mystery to me why the second alias isn't changing directories. The second alias is what I would like to get working. Thanks for any help you give.
Alias doesn't take arguments. It is replaced.
$ tryme /home/tbink1/Pictures
# tryme is _replaced_ by the alias, literally:
$ tb=$1;cd $tb;ls -latr /home/tbink1/Pictures
# then it's executed
# $1 is empty
+ tb=
# $tb is empty,
+ cd
# and ls lists the directory
+ ls -latr /home/tbink1/Pictures
cd with no arguments changes to home directory. $1 is your shell $1, i.e. bash -s this_is_first_arg:
$ bash -s this_is_first_arg
$ echo $1
this_is_first_arg
$ alias tryme='tb=$1;cd $tb'
$ tryme
bash: cd: this_is_first_arg: No such file or directory
Use a function, not an alias.

what's the "dot" command in Linux bash [duplicate]

Let's take a little example:
$ cat source.sh
#!/bin/bash
echo "I'm file source-1"
. source-2.sh
And:
$ cat source-2.sh
#!/bin/bash
echo "I'm file source-2"
Now run:
$ ./source.sh
I'm file source-1
I'm file source-2
If I'll change the call of the second file in first:
$ cat source.sh
#!/bin/bash
echo "I'm file source-1"
source source-2.sh
It will have the same effect as using dot.
What is difference between these methods?
The only difference is in portability.
. is the POSIX-standard command for executing commands from a file; source is a more-readable synonym provided by Bash and some other shells. Bash itself, however, makes no distinction between the two.
There is no difference.
From the manual:
source
source filename
A synonym for . (see Bourne Shell Builtins).

How to translate an alias into a real file?

Most of the time, an alias works well, but some times, the command is executed by other programs, and they find it in the PATH, in this situation an alias not works as well as a real file.
e.g.
I have the following alias:
alias ghc='stack exec -- ghc'
And I want to translate it into an executable file, so that the programs which depending on it will find it correctly. And the file will works just like the alias does, including how it process it's arguments.
So, is there any tool or scripts can help doing this?
Here is my solution, I created a file named ghc as following:
#!/bin/sh
stack exec -- ghc "$#"
The reason why there is double quote around $# is explained here: Propagate all arguments in a bash shell script
So, is there any tool or scripts can help doing this?
A lazy question for a simple problem... Here's a function:
alias2script() {
if type "$1" | grep -q '^'"$1"' is aliased to ' ; then
alias |
{ sed -n "s#.* ${1}='\(.*\)'\$##\!/bin/sh\n\1 \"\${\#}\"#p" \
> "$1".sh
chmod +x "$1".sh
echo "Alias '$1' hereby scriptified. To run type: './$1.sh'" ;}
fi; }
Let's try it on the common bash alias ll:
alias2script ll
Output:
Alias 'll' hereby scriptified. To run type: './ll.sh'
What's inside ll.sh:
cat ll.sh
Output:
#!/bin/sh
ls -alF "${#}"

How to find script directory in an included shell script

We now to find the directory of a shell script using dirname and $0, but this doesn't work when the script is inluded in another script.
Suppose two files first.sh and second.sh:
/tmp/first.sh :
#!/bin/sh
. "/tmp/test/second.sh"
/tmp/test/second.sh :
#!/bin/sh
echo $0
by running first.sh the second script also prints first.sh. How the code in second.sh can find the directory of itself? (Searching for a solution that works on bash/csh/zsh)
There are no solution that will work equally good in all flavours of shells.
In bash you can use BASH_SOURCE:
$(dirname "$BASH_SOURCE")
Example:
$ cat /tmp/1.sh
. /tmp/sub/2.sh
$ cat /tmp/sub/2.sh
echo $BASH_SOURCE
$ bash /tmp/1.sh
/tmp/sub/2.sh
As you can see, the script prints the name of 2.sh,
although you start /tmp/1.sh, that includes 2.sh with the source command.
I must note, that this solution will work only in bash. In Bourne-shell (/bin/sh) it is impossible.
In csh/tcsh/zsh you can use $_ instead of BASH_SOURCE.

How to get parent folder of executing script in zsh?

In bash i get the executing script's parent folder name by this line
SCRIPT_PARENT=`readlink -f ${BASH_SOURCE%/*}/..`
Is there any way to achieve this in zsh in a way that works both in zsh and bash?
Assume i have got a file /some/folder/rootfolder/subfolder/script with the contents:
echo `magic-i-am-looking-for`
I want it to behave this way:
$ cd /some/other/folder
$ . /some/folder/rootfolder/subfolder/script
/some/folder/rootfolder
$ . ../../folder/rootfolder/subfolder/script
/some/folder/rootfolder
$ cd /some/folder/rootfolder
$ . subfolder/script
/some/folder/rootfolder
$ cd subfolder
$ . script
/some/folder/rootfolder
This should work in bash and zsh. My first implements this behavior, but does due to $BASH_SOURCE not work in zsh.
So basically its:
Is there a way to emulate $BASH_SOURCE in zsh, that also works in bash?
I now realized that $0 in zsh behaves like $BASH_SOURCE in bash. So using $BASH_SOURCE when available and falling back to $0 solves my problem:
${BASH_SOURCE:-$0}
There is a little zsh edge case left, when sourcing from $PATH like:
zsh> cat ../script
echo \$0: $0
echo \$BASH_SOURCE: $BASH_SOURCE
echo '${BASH_SOURCE:-$0}:' ${BASH_SOURCE:-$0}
zsh> . script
$0: script
$BASH_SOURCE:
${BASH_SOURCE:-$0}: script
bash> . script
$0: bash
$BASH_SOURCE: /home/me/script
${BASH_SOURCE:-$0}: /home/me/script
I could do a which script but this would not play nice with other cases
While it would be easy to do this in zsh, it is just as easy to use pure bash which is able to be evaluated in zsh. If you cannot use any command that may or may not be on your path, then you can only use variable alteration to achieve what you want:
SCRIPT_SOURCE=${0%/*}
This is likely to be a relative path. If you really want the full path then you will have to resort to an external command (you could implement it yourself, but it would be a lot of work to avoid using a very available command):
SCRIPT_SOURCE=$(/bin/readlink -f ${0%/*})
This doesn't depend on your $PATH, it just depends on /bin/readlink being present. Which it almost certainly is.
Now, you wanted this to be a sourced file. This is fine, as you can just export any variable you set, however if you execute the above then $0 will be the location of the sourced file and not the location of the calling script.
This just means you need to set a variable to hold the $0 value which the sourced script knows about. For example:
The script you will source:
echo ${LOCATION%/*}
The script that sources that script:
LOCATION=$0
<source script here>
But given that the ${0%/*} expansion is so compact, you could just use that in place of the script.
Because you were able to run the command from your $PATH I'll do something like that:
SCRIPT_PARENT=$(readlink -f "$(which $0)/..")
Is that your desired output?

Resources