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.
Related
Running the command
cd \`echo -n "~"\`
I get the following error:
bash: cd: ~: No such file or directory
What's the problem if 'cd ~' works fine?
The issue is that bash does not do an additional expansion after command substitution. So while cd ~ is expanded the way you want, cd $(echo '~') does not.
There is a keyword called eval that was created for this sort of situation--it forces the command line to be expanded (evaluated) again. If you use eval on that line, it forces the ~ to be expanded into the user directory, even though the normal time for expansion has already passed. (Because the ~ does not exist until the echo command is run, and at that point, it's too late for expansion.)
eval cd `echo -n "~"`
If you do cd ~, the shell expands ~ to your home directory before executing the command. But if you use double quotes ("~"), then this is taken as a literal string and not expanded.
You can see the difference:
$ echo ~
/home/username
$ echo "~"
~
In order to have ~ expanded by the shell, you need to remove the double quotes.
The escaping behaviour of double quotes is described in the Bash manual: http://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
You will also get the same issue if you simply do cd "~":
$ cd "~"
bash: cd: ~: No such file or directory
cd doesn't understand that ~ is special. It tries, and fails, to find a directory literally called ~.
The reason that cd ~ works is that bash edits the command before running it. bash replaces cd ~ with cd $HOME, and then expands $HOME to get cd /home/YourUsername.
Therefore,
cd `echo -n "~"`
becomes
cd "~"
In my cygwin's .bashrc I have the following two aliases:
alias dospath='cygpath -w `pwd`'
alias dospathcp='dospath > /dev/clipboard'
The first one is supposed to print the dos (or windows) path of the directory in which it is executed. This one works as expected.
The second alias is then supposed to redirect the output of dospath into /dev/clipboard so that I can paste it in windows applications. This one does not work. When I type dospathcp in bash, it just empties /dev/clipboard (and the clipbaord itself).
Try as follows:
alias dospath='cygpath -w $PWD'
alias dospathcp='dospath > /dev/clipboard'
This produces following output in my CYGWIN_NT-6.1-WOW64 CC 1.7.25(0.270/5/3) 2013-08-31 20:39 i686 Cygwin
$ alias dospath='cygpath -w $PWD'
$ cd /home/somedir
$ dospath
W:\cygwin\home\somedir
$ cd /home/anotherdir
$ dospath
W:\cygwin\home\anotherdir
$ alias dospathcp='dospath > /dev/clipboard'
$ cd /home/somedir
$ dospathcp
$ cat /dev/clipboard
W:\cygwin\home\somedir
$ cd /home/anotherdir
$ dospathcp
$ cat /dev/clipboard
W:\cygwin\home\anotherdir
See http://ss64.com/bash/alias.html
The first word of the replacement text is tested for aliases, but a
word that is identical to an alias being expanded is not expanded a
second time. This means that one may alias ls to "ls -F", for
instance, and Bash does not try to recursively expand the replacement
text.
I have 2 lines of code
1) With the following code:
for i in `ls *.properties`; do cat $i; done
I get the error:
cat: file_name.properties: No such file or directory.
2) On the other hand:
for i in *.properties; do cat $i; done
Works fine!
I thought both were the same. Can someone help me understand the difference between the two? Using bash shell.
What does the following command print?
cat -v <<< `ls *.properties`
I guess the problem is, that ls is a strange alias, e.g. something like
ls='ls --color'
Edit: I have seen this before. The alias should be: alias ls='ls --color=auto'
Most probably there is a directory which matches *.properties. Then ls will output the files in this directory without the directory name. Then the cat will not find the given filename.
So please check, whether file_name.properties is in the actual directory or in some subdirectory.
EDIT
To reproduce the problem you can try this:
# cd /tmp
# mkdir foo.properties
# touch foo.properties/file_name.properties
# for i in `ls *.properties`; do cat $i; done
cat: file_name.properties: No such file or directory
$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.
How can I find out where an alias is defined on my system? I am referring to the kind of alias that is used within a Terminal session launched from Mac OS X (10.6.3).
For example, if I enter the alias command with no parameters at a Terminal command prompt, I get a list of aliases that I have set, for example:
alias mysql='/usr/local/mysql/bin/mysql'
However, I have searched all over my system using Spotlight and mdfind in various startup files and so far can not find where this alias has been defined. ( I did it a long time ago and didn't write down where I assigned the alias).
For OSX, this 2-step sequence worked well for me, in locating an alias I'd created long ago and couldn't locate in expected place (~/.zshrc).
cweekly:~ $ which la
la: aliased to ls -lAh
cweekly:~$ grep -r ' ls -lAh' ~
/Users/cweekly//.oh-my-zsh/lib/aliases.zsh:alias la='ls -lAh'
Aha! "Hiding" in ~/.oh-my-zsh/lib/aliases.zsh. I had poked around a bit in .oh-my-zsh but had overlooked lib/aliases.zsh.
you can just simply type in alias on the command prompt to see what aliases you have. Otherwise, you can do a find on the most common places where aliases are defined, eg
grep -RHi "alias" /etc /root
First use the following commands
List all functions
functions
List all aliases
alias
If you aren't finding the alias or function consider a more aggressive searching method
Bash version
bash -ixlc : 2>&1 | grep thingToSearchHere
Zsh version
zsh -ixc : 2>&1 | grep thingToSearchHere
Brief Explanation of Options
-i Force shell to be interactive.
-c Take the first argument as a command to execute
-x -- equivalent to --xtrace
-l Make bash act as if invoked as a login shell
Also in future these are the standard bash config files
/etc/profile
~/.bash_profile or ~/.bash_login or ~/.profile
~/.bash_logout
~/.bashrc
More info: http://www.heimhardt.com/htdocs/bashrcs.html
A bit late to the party, but I was having the same problem (trying to find where the "l." command was aliased in RHEL6), and ended up in a place not mentioned in the previous answers. It may not be found in all bash implementations, but if the /etc/profile.d/ directory exists, try grepping there for unexplained aliases. That's where I found:
[user#server ~]$ grep l\\. /etc/profile.d/*
/etc/profile.d/colorls.csh:alias l. 'ls -d .*'
/etc/profile.d/colorls.csh:alias l. 'ls -d .* --color=auto'
/etc/profile.d/colorls.sh: alias l.='ls -d .*' 2>/dev/null
/etc/profile.d/colorls.sh:alias l.='ls -d .* --color=auto' 2>/dev/null
The directory isn't mentioned in the bash manpage, and isn't properly part of where bash searches for profile/startup info, but in the case of RHEL you can see the calling code within /etc/profile:
for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
if [ "${-#*i}" != "$-" ]; then
. "$i"
else
. "$i" >/dev/null 2>&1
fi
fi
done
Please do check custom installations/addons/plugins you have added, in addition to the .zshrc/.bashrc/.profile etc files
So for me: it was git aliased to 'g'.
$ which g
g: aliased to git
Then I ran the following command to list all aliases
$ alias
I found a whole lot of git related aliases that I knew I had not manually added.
This got me thinking about packages or configurations I had installed. And so went to the
.oh-my-zsh
directory. Here I ran the following command:
$ grep -r 'git' . |grep -i alias
And lo and behold, I found my alias in :
./plugins/git/git.plugin.zsh
I found the answer ( I had been staring at the correct file but missed the obvious ).
The aliases in my case are defined in the file ~/.bash_profile
Somehow this eluded me.
For more complex setups (e.g. when you're using a shell script framework like bash-it, oh-my-zsh or the likes) it's often useful to add 'alias mysql' at key positions in your scripts. This will help you figure out exactly when the alias is added.
e.g.:
echo "before sourcing .bash-it:"
alias mysql
. $HOME/.bash-it/bash-it.sh
echo "after sourcing bash:"
alias mysql
I think that maybe this is similar to what ghostdog74 meant however their command didn't work for me.
I would try something like this:
for i in `find . -type f`; do # find all files in/under current dir
echo "========"
echo $i # print file name
cat $i | grep "alias" # find if it has alias and if it does print the line containing it
done
If you wanted to be really fancy you could even add an if [[ grep -c "alias" ]] then <print file name>
The only reliable way of finding where the alias could have been defined is by analyzing the list of files opened by bash using dtruss.
If
$ csrutil status
System Integrity Protection status: enabled.
you won't be able to open bash and you may need a copy.
$ cp /bin/bash mybash
$ $ codesign --remove-signature mybash
and then use
sudo dtruss -t open ./mybash -ic exit 2>&1 | awk -F'"' '/^open/ {print substr($2, 0, length($2)-2)}'
to list all the files where the alias could have been defined, like
/dev/dtracehelper
/dev/tty
/usr/share/locale/en_CA.UTF-8/LC_MESSAGES/BASH.mo
/usr/share/locale/en_CA.utf8/LC_MESSAGES/BASH.mo
/usr/share/locale/en_CA/LC_MESSAGES/BASH.mo
/usr/share/locale/en.UTF-8/LC_MESSAGES/BASH.mo
/usr/share/locale/en.utf8/LC_MESSAGES/BASH.mo
/usr/share/locale/en/LC_MESSAGES/BASH.mo
/Users/user/.bashrc
/Users/user/.bash_aliases
/Users/user/.bash_history
...
Try: alias | grep name_of_alias
Ex.: alias | grep mysql
or, as already mentioned above
which name_of_alias
In my case, I use Oh My Zsh, so I put aliases definition in ~/.zshrc file.