# deferring argument in "alias" in .bashrc

I work with LINUX (ubuntu 14) My newly purchased laptop forces me to use the bash shell, and it has .bashrc. I used to use the C-shell before that and tried to copy its aliases from .cshrc to .bashrc with some obvious editing.

One thing doesn't work though -- the deferred argument. As an example - my .cshrc command:

alias rm 'mv -f \!* $HOME/zap'  when written in .bshrc as alias rm = 'mv -f \!*$HOME/zap'


generates an error message:

bash:alias: rm: not found
bash:alias: mv -f \!* $HOME/zap: not found  (the directory zap was created by me in advance) What should I use instead of \!*? • It is not your laptop that forces you to use bash, it is just the default for a user on Ubuntu 14. If you install csh and change your entry in /etc/password you can continue to use csh as a login shell. Jul 28, 2016 at 16:13 • Also, while t?csh lumps everything in aliases, the *sh shells tend to use functions and not aliases for anything complicated. Jul 28, 2016 at 16:17 • Anthon, thanks. But I am afraid of many dependencies or whatever they call it, and I'd rather prefer to start with the default setting at this point. My issue seems to be very simple, there should be a simple answer I guess.... Jul 28, 2016 at 16:45 • Kusalananda, thanks! You might be right, but I see already many aliases in my .bshrc, and added a lot of my own; and my trouble doesn't look to me like a big issue... Jul 28, 2016 at 16:48 • @Anthon In my opinion, your comment is the best answer so far. Jul 29, 2016 at 6:21 ## 2 Answers You should use shell functions instead of aliases in these cases. It's a bit more to type, but it allows you to be more flexible: function rm { if ! test -d "$HOME/zap"; then
echo "No zap in home" >&2
return 1
else
mv -f -- "$@" "$HOME/zap/"
fi
}


The $@ will expand to the arguments you give rm on the command line. The -- is necessary to signal an end to command line flags (so that rm -f, where -f is a file, is possible, rm and mv don't share many command line flags anyway). To access the original rm command, use \rm or command rm. The testing for the existence of $HOME/zap, outputting an error message to standard error, and exiting with non-zero exit status in the function is just to show that you could do anything you'd want in there. You could obviously slim it down to just

function rm {
mv -f -- "$@" "$HOME/zap/"
}


The bash manual contains the statement:

For almost every purpose, aliases are superseded by shell functions.

Aliases are really only useful for e.g. tagging on your favourite flags to ls and things like that.

• Dear Kusalananda, it worked! thanks!!! (still, I'll be missing aliases..) Jul 28, 2016 at 17:08
• @AlKap Good! If this solves your issue, please consider accepting the answer. Jul 29, 2016 at 6:15
• sorry for being really dumb, but how I "accept the answer" -- cannot find an appropriate button.. Jul 29, 2016 at 7:21
• @AlKap No worries. There is a grayed-out "check mark" underneath the up/down-vote buttons in the left column by the answer. Clicking it will turn it green. Jul 29, 2016 at 7:30

If you remove un-needed spaces, the command will have some hope of working:

$alias rm='mv -f \!*$HOME/zap'


Lets just add an echo to "see" what happens without moving files:

$alias rm='echo mv -f \!*$HOME/zap'
$rm one two three mv -f !* /home/immf/zap one two three  Which simply goes to show that bash history doesn't work in the same way as csh's history commands because csh use: If the alias contains a history reference, it undergoes History substitution as though the original command were the previous input line. and bash does not. Even more, bash aliases have this limits: There is no mechanism for using arguments in the replacement text. If arguments are needed, a shell function should be used. Aliases are not expanded when the shell is not interactive. That is: there is no way to reuse arguments in the present line, and even more, aliases do not work in scripts (by default). However, the intent of the alias is to re-use the same arguments and add a last directory as the target where to move the files: $ alias rm 'echo mv -f \!* $HOME/zap' ### in csh$ rm one two 333                             ### in csh
mv -f one two 333 /home/user/zap


Which could be easily done with the -t option of mv (not available in bsd's mv):

$alias rm='echo mv -f -t "$HOME/zap"'
\$ rm one two 333
mv -f -t /home/user/zap one two 333


In short: It would be wise to use a function.

• it helps, thanks, especially for the option "-t". Jul 29, 2016 at 7:05