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.
Related
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.
Expected behavior
List the documents in a directory using an environmental variable.
Steps to Reproduce
INPUT
$ export ICLOUD_D="~/Library/Mobile\ Documents/com~apple~CloudDocs/"
$ source ~/.zshrc
$ echo $ICLOUD_D
$ ls $ICLOUD_D
OUTPUT
$ ~/Library/Mobile\ Documents/com~apple~CloudDocs/
$ ls: ~/Library/Mobile\ Documents/com~apple~CloudDocs/: No such file or directory
Current behavior
Shell gives me a: No such file or directory error.
Steps Performed Thus Far to Fix
If I were to simply cut and paste the file path with the command ls then I'm able to list the files as expected.
I've also tried to put quotes around the environmental variable as well.
$ ls "$ICLOUD_D"
System information
- OS: MacOS v 10.15
- Shell: zsh
Do not put quotes around the environmental variable
INPUT
$ export ICLOUD_D=~/Library/Mobile\ Documents/com~apple~CloudDocs/
$ source ~/.zshrc
$ echo $ICLOUD_D
$ ls $ICLOUD_D
OUTPUT
$ ~/Library/Mobile\ Documents/com~apple~CloudDocs/
$ afile
$ bfile
$ ...
In linux, I have a file-list named file_list.txt, where the paths in that list include also an env variable (for this example, the file listed in that file-list is $HOME/myfile).
> cat file_list.txt
$HOME/myfile
> ls `cat file_list.txt`
ls: $HOME/myfile: No such file or directory
> ls $HOME/myfile
/home/user/myfile
Why is that? How can I run operations (such as ls, less, vim etc) on the files listed in the file-list?
If you want to expand the variables you will need something like:
$ sh -c "ls `cat file_list.txt`"
In this case, the commands are read from string and therefore extending variables if any.
$ eval "ls `cat file_list.txt`"
Just in case check also this question: Why should eval be avoided in Bash, and what should I use instead?
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 "~"
$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.