How do I set tilde expansion in zsh? - linux

I am trying to achieve expansion of the tilde into the $HOME variable with zsh, and was wondering what best practice is in this case?
Basically what I want is that:
$ ls ~
on pressing TAB expands to
$ ls /home/myusername
where HOME=/home/myusername. The _tilde function usually does a ldap search, followed by named dirs, followed by the dir stack, none of which I need.
What is the best way to achieve this?

Related

Find command in Command substitution bash script

Hope you are doing well. I am kind of new to bash scripting so I wanted to ask you a question on something I stumbled upon just recently when I was playing around with the find command. What I had noticed was that when I search for a script name using the find command using the command substitution in the bash script, and call the variable from command substitution, it will find the script full path and also execute it right after. Can you please let me know why and how this is working?
E.g.
SEARCH=$(find / -type f -iname "script.name" 2> /dev/null)
$SEARCH
Regards
Bash performs expansions before it builds and executes the command. If you execute cd "$HOME" for example, you probably want to go to the directory stored in the variable HOME and not to a directory literally named $HOME. This allows you to put a command name inside a variable and run it by expanding the variable as the first word, although this isn't really recommended because it becomes very complex to manage for anything more than the simplest commands. The code in your question would probably not work as intended if find returned multiple results for example.
See BashParser on the BashFAQ.

Using an environment variable in an rsync argument (dealing with quotes and escape character)

I want to use rsync with an --exclude command that looks like
rsync -av --exclude={"*.ext1","*.ext2", "*.ext3"} source target
(For some reason it is more handy to me to use such a syntax than using the --exclude-from=FILE syntax)
I would like to use an environement variable with rsync so that I could do
export toto='{"*.ext1","*.ext2", "*.ext3"}'
rsync -av --exclude=$toto source target
The problem is that it doesn't work the way I wish. When I use the automatic completion over the $toto variable it shows :
\{\"\*.ext1\",\"\*.ext2\",\ \"\*.ext3\"\}
It is actually what rsync understands and it gets totally confused.
Could anybody explain the rational behind this "quotes and escape characters" behavior?
This works:
MYEXCLUDE={'*.ext1','*.ext2'}
eval rsync -av --exclude=$MYEXCLUDE src dest
As already mentioned, {,} triggers brace expansion (btw, the space before ext3 in your example is a problem: it prevents brace exp).
And rsync's exclude option only accepts a single pattern (this means that everything can be understood by replacing rsync and echo).
By chance, when the 1st line sets the variable, brace expansion does not yet take place (echo $MYEXCLUDE shows : {*.ext1,*.ext2}).
And brace expansion happens after variable expansion. So the trick is to use eval to have the expansion just-in-time. To fully understand, compare the following 2 lines:
MYEXCLUDE=--exclude={'*.ext1','*.ext2'}
echo $MYEXCLUDE
eval echo $MYEXCLUDE
displays
--exclude={*.ext1,*.ext2}
--exclude=*.ext1 --exclude=*.ext2
If I understand your question, you cannot use brace expansion in the content of the environment variable.
Why? Brace Expansion is provided by your shell (bash). When rsync reads the content of --exclude=$toto no shell expansions are applied. A better approach would be to generate the list of files to exclude, redirect the output to a file and --exlcude-from=file where file would contain a single filename (or rule) on each line.
All of the quoting and escaping that is applied is from the attempt by rsync to make valid Unix filenames or patterns from {"*.ext1","*.ext2","*.ext3"}. (basically you have confused the heck out of rsync and it is doing its best with the mess you have given it).
When you have what should be a brace expansion stored in a variable, no shell expansions will be applied, quotes lose their meaning and rsync is left trying to sort out the mess.
Look at the --exclude, --exclude-from and --filter in rsync(1) - Linux manual page

customizing ZSH tilde expansion

Context
This concerns ZSH tilde expansion (as in bash tilde expansion).
Example: ~http is expanded to /srv/http which is (roughly) the home for user http set in /etc/passwd.
What I want to do
I would like to configure ZSH in order to get any filename tilde expansion I wish.
This would be something like setting alias ~foo /foo/bar in my .zshrc.
What I do not want
I could create (as root) the user foo and set it’s home to /foo/bar but since any user should be able to do this, such a solution is not acceptable.
Also, this has nothing to do with the completion of ~ to $HOME.
Misc
This post discuss the nature of bash tilde expansion: Meaning of tilde in Linux bash (not home directory).
Thanks for any answer! ;-)
You could use either (or both) way:
hash -d foo=/foo/bar (hash builtin command)
foo=/foo/bar/
Now, we could use cd ~foo to change the current directory to /foo/bar, too.
It is known as “Static named directories” in zsh.
Note: when CDABLE_VARS shell option is active, we could do even cd foo rather than cd ~foo in the above example if the directory (/foo/bar in this example) exists.

find command works differently in zsh and bash

I just switched my shell from bash to zsh and I noticed some different behavior as to how the find command works.
In my old bash shell I had a function that basically replicates the behavior of the find command. For some strange reason the find command does not work in zsh but works in my old bash
Command in bash
~ /java_src: f stringBuf*
./com/sun/org/apache/xml/internal/utils/StringBufferPool.java
./java/io/StringBufferInputStream.java
./java/lang/StringBuffer.java
Same command in zsh
~ /java_src: f stringBuf*
zsh: no matches found: stringBuf*
This is the function
# find shorthand
function f() {
find . -iname "$1"
}
Any suggestions on why that might be the case?
Try quoting the argument, as in f 'stringBuf*', to avoid premature glob expansion.
If you call it unquoted, bash will do the smart thing and, after looking for the pattern in your current directory and not finding anything, will pass the parameter to the function as is.
zsh on the other hand, will try to match the pattern in your current directory, then complain about not finding anything, and not execute the function at all.
It is generally not a good idea to use unquoted wildcards (unless you mean it), since, if you have a file in your current directory called, say, "stringBuffoon", your parameter to f will be turned into "stringBuffoon", and the search will not give you the results you expect.

Linux alias chain commands (can recursion be avoided?)

I've been looking around for ways to alias clear and ls into one command.
Currently I've defined command x:
alias x="clear;ls"
Now is there any walkaround to avoid recursion and define:
alias ls='clear;ls'
If you put a backslash before the command name, that will disable any aliases.
alias ls='clear;\ls'
Or, like Arnaud said, just use the full path for ls.
Another way of doing this would be
alias ls='clear; command ls'
This is different from /usr/bin/ls, as it still searches ls in the $PATH, but will ignore shell functions or aliases.
Just do :
alias ls='clear;/usr/bin/ls'
When typing:
$ ls
First of all it will search an user defined function, it will launch it, else search in $PATH commands.
By giving the explicit path of the ls command, recursion will be avoided.
There is no direct recursion in alias. From man bash:
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 always use ls with --color=auto parameter ( -G Enable colorized output.) and like to use functions.
clear_and_ls() {
clear
command ls --color=auto
}
alias ls="clear_and_ls"

Resources