4

This question already has an answer here:

Making alias of rm command so that when rm command is executed it will first copy file to /tmp/recycle_bin and then remove the file. But I'm getting issue in the process.

Steps performed by me:

  1. I wrote below command in ~/.bashrc file:

    alias rm='cp $@ /tmp/recycle_bin && rm $@'
    
  2. execute it with below command:

    . ~/.bashrc
    
  3. Open new terminal and execute below command:

    rm "/home/XXXXX/My_Programs/test_method.py"
    cp: missing destination file operand after '/tmp/recycle_bin'** got this error message 
    

Need to understand:

  1. Even if the parameter is passed to rm command as the file which I want to remove. Why i am getting error **missing destination file operand after /tmp/recycle_bin?

  2. The $@ variable in alias command is not populated? How to debug this case and resolve?

marked as duplicate by Barmar, G-Man, slm Jul 7 '18 at 6:37

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 6
    Use function, not alias. – Ipor Sircer Jul 6 '18 at 10:22
  • 6
    Beware of creating aliases for dangerous commands. Make sure that the target audience knows it is a customization. There is a real risk of users using sudo or switching to a root shell and running the raw rm instead, with obvious consequences. – Henk Langeveld Jul 6 '18 at 11:37
  • 2
    See also Question: Make rm move to trash – Konrad Rudolph Jul 6 '18 at 15:04
  • 6
    IMO this is a bad idea, especially if you're going to be using different unix machines over time. You will (likely) get in the mental habit of not being as careful with rm as you should, and then you will switch to a user, or be on a machine where you don't have that alias and Ooops. As @IporSircer notes, use a function, and call it something like "trash". This separates "rm" and "trash" in your mind, and if you wind up on a server w/out the "trash" function you do no harm. – Petro Jul 6 '18 at 15:50
  • 1
    @Petro: And writing a "trash" function would allow you to put some more logic in there, so if for instance you did "trash *.o *.tmp *.bak", you function could remove the easily-recreated .o and .tmp files, and mv (not cp!) the .bak files to your "recycle_bin" directory. (Also, would a bash alias even handle multiple expanded arguments?) – jamesqf Jul 6 '18 at 16:36
23

An alias can not take arguments and use $@ to access them like that.

Alias expansion in bash is a simple text replacement. If you have alias rm ='something something', then using rm file1 file2 would execute

something something file1 file2

and if the alias included $@, this would be expanded with the command line arguments of the shell, not of the alias.

In your case, assuming the shell's list of command line arguments is empty, the alias

alias rm='cp $@ /tmp/recycle_bin && rm $@'

would execute as

cp /tmp/recycle_bin && rm file1 file2

when invoked as rm file1 file2. The cp utility will complain about only having a single operand.


You could use a shell function instead:

rm () {
    cp -- "$@" "${TMPDIR:-/tmp}/recycle_bin" &&
    command rm -- "$@"
}

This would copy the indicated files to $TMPDIR/recycle_bin (or /tmp/recycle_bin if TMPDIR is unset or empty) and then delete the files. The command command is used to not cause an infinite recursion. The -- are needed to treat all arguments as filenames rather than as options. Note also that the quoting is important so that filenames are not split on whitespaces and so that filename globbing patterns in the arguments are not picking up files that you don't want to remove.

A bit more efficient (cp+rm == mv):

rm () {
    mv -- "$@" "${TMPDIR:-/tmp}/recycle_bin"
}

A bit more safe (creates the recycle bin if it's not there):

rm () {
    mkdir -p "${TMPDIR:-/tmp}/recycle_bin" &&
    mv -- "$@" "${TMPDIR:-/tmp}/recycle_bin"
}

And even safer, with GNU mv (creates backups in the recycle bin if name collisions occur):

rm () {
    mkdir -p "${TMPDIR:-/tmp}/recycle_bin" &&
    mv -b -- "$@" "${TMPDIR:-/tmp}/recycle_bin"
}

For an alias-only (and GNU-only) variation, see "Create a recycle bin feature without using functions".

2

Bash and most Bourne derived shells do not support parameterized aliases.

You cannot do things this way.

A working method was to define an alias that expands do:

sh -c 'cp -- "$@" /tmp/recycle_bin && rm -- "$@"' sh

This results in the following command:

myrm='sh -c '\''cp -- "$@" /tmp/recycle_bin && rm -- "$@"'\'' sh'

Note that this could be done without the overhead of creating a new shell process if you use a recent version of the Bourne Shell (bosh). This shell includes a builtin command dosh that acts like the one line script from a sh -c call. This concept of parameterizable aliases has been invented by former AT&T employees in 1980 and implemented in their real time UNIX clone called UNOS.

With boshyou could use:

myrm='dosh '\''cp -- "$@" /tmp/recycle_bin && rm -- "$@"'\'' myrm'

BTW: The Bourne Shell helps you with typing the alias command in raw mode and auto creating the needed escape sequences for the single quote characters. I did not write this ugly command line with escapes myself, but let bosh create it from the raw command line above.

Not the answer you're looking for? Browse other questions tagged or ask your own question.