Haga un alias de Bash que tome un parámetro?



5 Answers

Al refinar la respuesta anterior, puede obtener la sintaxis de 1 línea como puede para los alias, que es más conveniente para las definiciones ad-hoc en un shell o archivos .bashrc:

bash$ myfunction() { mv "$1" "$1.bak"; cp "$2" "$1"; }

bash$ myfunction original.conf my.conf

No olvides el punto y coma antes del cierre del corchete derecho. Del mismo modo, para la pregunta real:

csh% alias junk="mv \\!* ~/.Trash"

bash$ junk() { mv "$@" ~/.Trash/; }

O:

bash$ junk() { for item in "$@" ; do echo "Trashing: $item" ; mv "$item" ~/.Trash/; done; }
Question

Solía ​​usar CShell ( csh ), que te permite crear un alias que toma un parámetro. La notación era algo así como

alias junk="mv \\!* ~/.Trash"

En Bash, esto no parece funcionar. Dado que Bash tiene una multitud de características útiles, supongo que esta ha sido implementada, pero me pregunto cómo.




Para tomar parámetros, ¡debe usar funciones!

Sin embargo, $ @ se interpreta cuando se crea el alias en lugar de durante la ejecución del alias y tampoco escapa $. ¿Cómo resuelvo este problema?

Necesita usar la función de shell en lugar de un alias para deshacerse de este problema. Puedes definir foo de la siguiente manera:

function foo() { /path/to/command "$@" ;}

O

foo() { /path/to/command "$@" ;}

Finalmente, llame a su foo () usando la siguiente sintaxis:

foo arg1 arg2 argN

Asegúrese de agregar su archivo foo () a ~/.bash_profile o ~/.zshrc .

En tu caso, esto funcionará

function trash() { mv $@ ~/.Trash; }



Aquí hay tres ejemplos de funciones que tengo en mi ~/.bashrc , que son esencialmente alias que aceptan un parámetro:

#Utility required by all below functions.
#https://.com/questions/369758/how-to-trim-whitespace-from-bash-variable#comment21953456_3232433
alias trim="sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'"

.

:<<COMMENT
    Alias function for recursive deletion, with are-you-sure prompt.

    Example:
        srf /home/myusername/django_files/rest_tutorial/rest_venv/

    Parameter is required, and must be at least one non-whitespace character.

    Short description: Stored in SRF_DESC

    With the following setting, this is *not* added to the history:
        export HISTIGNORE="*rm -r*:srf *"
    - https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash

    See:
    - y/n prompt: https://.com/a/3232082/2736496
    - Alias w/param: https://.com/a/7131683/2736496
COMMENT
#SRF_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
SRF_DESC="srf [path]: Recursive deletion, with y/n prompt\n"
srf()  {
    #Exit if no parameter is provided (if it's the empty string)
        param=$(echo "$1" | trim)
        echo "$param"
        if [ -z "$param" ]  #http://tldp.org/LDP/abs/html/comparison-ops.html
        then
          echo "Required parameter missing. Cancelled"; return
        fi

    #Actual line-breaks required in order to expand the variable.
    #- https://.com/a/4296147/2736496
    read -r -p "About to
    sudo rm -rf \"$param\"
Are you sure? [y/N] " response
    response=${response,,}    # tolower
    if [[ $response =~ ^(yes|y)$ ]]
    then
        sudo rm -rf "$param"
    else
        echo "Cancelled."
    fi
}

.

:<<COMMENT
    Delete item from history based on its line number. No prompt.

    Short description: Stored in HX_DESC

    Examples
        hx 112
        hx 3

    See:
    - https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
COMMENT
#HX_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
HX_DESC="hx [linenum]: Delete history item at line number\n"
hx()  {
    history -d "$1"
}

.

:<<COMMENT
    Deletes all lines from the history that match a search string, with a
    prompt. The history file is then reloaded into memory.

    Short description: Stored in HXF_DESC

    Examples
        hxf "rm -rf"
        hxf ^source

    Parameter is required, and must be at least one non-whitespace character.

    With the following setting, this is *not* added to the history:
        export HISTIGNORE="*hxf *"
    - https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash

    See:
    - https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
COMMENT
#HXF_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
HXF_DESC="hxf [searchterm]: Delete all history items matching search term, with y/n prompt\n"
hxf()  {
    #Exit if no parameter is provided (if it's the empty string)
        param=$(echo "$1" | trim)
        echo "$param"
        if [ -z "$param" ]  #http://tldp.org/LDP/abs/html/comparison-ops.html
        then
          echo "Required parameter missing. Cancelled"; return
        fi

    read -r -p "About to delete all items from history that match \"$param\". Are you sure? [y/N] " response
    response=${response,,}    # tolower
    if [[ $response =~ ^(yes|y)$ ]]
    then
        #Delete all matched items from the file, and duplicate it to a temp
        #location.
        grep -v "$param" "$HISTFILE" > /tmp/history

        #Clear all items in the current sessions history (in memory). This
        #empties out $HISTFILE.
        history -c

        #Overwrite the actual history file with the temp one.
        mv /tmp/history "$HISTFILE"

        #Now reload it.
        history -r "$HISTFILE"     #Alternative: exec bash
    else
        echo "Cancelled."
    fi
}

Referencias




TL; DR: Haz esto en cambio

Es mucho más fácil y más legible usar una función que un alias para poner argumentos en el medio de un comando.

$ wrap_args() { echo "before $@ after"; }
$ wrap_args 1 2 3
before 1 2 3 after

Si sigue leyendo, aprenderá cosas que no necesita saber sobre el procesamiento de argumentos de shell. El conocimiento es peligroso. Obtenga el resultado que desea, antes de que el lado oscuro controle para siempre su destino.

Aclaración

bash alias de bash aceptan argumentos, pero solo al final :

$ alias speak=echo
$ speak hello world
hello world

Poner argumentos en el medio del comando a través de alias es posible, pero se pone feo.

¡No intentes esto en casa, niños!

Si le gusta eludir las limitaciones y hacer lo que otros dicen que es imposible, esta es la receta. No me culpes si tu cabello se agota y tu cara queda cubierta de hollín al estilo científico.

La solución consiste en pasar los argumentos de que alias solo acepta al final una envoltura que los insertará en el medio y luego ejecutará su comando.

Solución 1

Si realmente está en contra de usar una función per se, puede usar:

$ alias wrap_args='f(){ echo before "$@" after;  unset -f f; }; f'
$ wrap_args x y z
before x y z after

Puede reemplazar $@ con $1 si solo quiere el primer argumento.

Explicación 1

Esto crea una función temporal f , que pasa los argumentos (tenga en cuenta que f se llama al final). El unset -f elimina la definición de la función ya que el alias se ejecuta para que no se cuelgue después.

Solución 2

También puedes usar una subshell:

$ alias wrap_args='sh -c '\''echo before "$@" after'\'' _'

Explicación 2

El alias crea un comando como:

sh -c 'echo before "$@" after' _

Comentarios:

  • El marcador de posición _ es obligatorio, pero podría ser cualquier cosa. Se establece en sh $0 y es necesario para que el primer argumento dado por el usuario no se consuma. Demostración:

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
    
  • Se requieren las comillas simples dentro de las comillas simples. Aquí hay un ejemplo de que no funciona con comillas dobles:

    $ sh -c "echo Consumed: $0 Printing: $@" alcohol drunken babble
    Consumed: -bash Printing:
    

    Aquí, los valores de los $0 y $@ del shell interactivo se reemplazan en el doble citado antes de pasar a sh . Aquí hay una prueba:

    echo "Consumed: $0 Printing: $@"
    Consumed: -bash Printing:
    

    Las comillas simples aseguran que estas variables no sean interpretadas por el shell interactivo, y se pasan literalmente a sh -c .

    Podría usar comillas dobles y \$@ , pero la mejor práctica es citar sus argumentos (ya que pueden contener espacios), y \"\$@\" ve aún más feo, pero puede ayudarlo a ganar un concurso de ofuscación donde el cabello agotado es un requisito previo para la entrada.




Sin embargo, no necesita funciones al crear alias en el archivo .bashrc . Por ejemplo

# create an alias that takes port-number by the user
alias serve="python -m SimpleHTTPServer $1"

Después de realizar el cambio en el archivo .bashrc, asegúrese de ingresar el siguiente comando.

~$ source .bashrc

Deberías poder usar esto como tal

~$ serve 8998



Si está buscando una forma genérica para aplicar todos los parámetros a una función, no solo uno, dos o algún otro monto codificado, puede hacerlo de esta manera:

#!/usr/bin/env bash

# you would want to `source` this file, maybe in your .bash_profile?
function runjar_fn(){
    java -jar myjar.jar "$@";
}

alias runjar=runjar_fn;

Entonces, en el ejemplo anterior, paso todos los parámetros desde cuando ejecuto runjar al alias.

Por ejemplo, si runjar hi there terminaría ejecutando java -jar myjar.jar hi there . Si hiciera runjar one two three , ejecutaría java -jar myjar.jar one two three .

Me gusta esta solución basada en $@ porque funciona con cualquier cantidad de params.




Related



Tags

bash bash   alias