Creare un alias Bash che accetta un parametro?


1273

Ho usato CShell (), che consente di creare un alias che accetta un parametro. La notazione era qualcosa di simile

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

In Bash, questo non sembra funzionare. Dato che Bash ha una moltitudine di funzioni utili, suppongo che questo sia stato implementato ma mi chiedo come.



2
Assicurati di usare le virgolette intorno agli args"$1"
Christophe Roussy,

Questa domanda è fuori tema per SO. E 'stato risposto sul UNIX.SE , e la risposta è che non c'è nemmeno bisogno di preoccuparsi: "Per esempio, se si dovesse alias lsa ls -la, quindi digitando ls foo barsarebbe davvero eseguire ls -la foo bar. Sulla riga di comando"
Dan Dascalescu,

7
che non aiuterebbe a interpolare una variabile nel mezzo di una stringa
Franz Sittampalam,

1
Ecco l'alias lil test che ho usato per scoprire questo errore ... alias test_args="echo PREFIX --$1-- SUFFIX", che quando chiamato con test_args ABCDproduce il seguente output di consolePREFIX ---- SUFFIX ABCD
jxramos,

Risposte:


2126

Alias ​​Bash non accetta direttamente i parametri. Dovrai creare una funzione.

aliasnon accetta parametri ma una funzione può essere chiamata proprio come un alias. Per esempio:

myfunction() {
    #do things with parameters like $1 such as
    mv "$1" "$1.bak"
    cp "$2" "$1"
}


myfunction old.conf new.conf #calls `myfunction`

A proposito, le funzioni di Bash definite nel tuo .bashrce in altri file sono disponibili come comandi all'interno della tua shell. Quindi, ad esempio, puoi chiamare la funzione precedente in questo modo

$ myfunction original.conf my.conf

48
Dovrei finire $1tra virgolette?
Jürgen Paul,

263
Non devi nemmeno dichiarare l'alias. Sarà sufficiente definire la funzione.
dinigo,

207
Se stai cambiando un alias in una funzione, sourceing .bashrc aggiungerà la funzione ma non unalias il vecchio alias. Poiché gli alias hanno un precedente superiore rispetto alle funzioni, tenterà di utilizzare l'alias. È necessario chiudere e riaprire la shell, oppure chiamare unalias <name>. Forse salverò qualcuno i 5 minuti che ho appena sprecato.
Marty Neal,

56
@MartinNeal: un trucco che ho imparato da Sun in poco tempo è quello di fare semplicemente una exec bash: inizierà una nuova shell, dandoti una lettura chiara delle tue configurazioni, proprio come se avessi chiuso e riaperto, ma mantenendo anche le impostazioni delle variabili d'ambiente di quella sessione . Inoltre, eseguire bashsenza il exec può essere utile quando si desidera gestire pensa come uno stack.
Macneil Shonle,

21
@mich - sì, metti sempre le variabili bash tra virgolette. es mv "$1" "$1.bak". senza virgolette, se $ 1 fosse "ciao mondo", eseguiresti mv hello world hello world.bakinvece di mv "hello world" "hello world.bak".
Orion Elenzil,

208

Affinando la risposta sopra, puoi ottenere la sintassi di 1 riga come puoi per gli alias, che è più conveniente per le definizioni ad hoc in una shell o file .bashrc:

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

bash$ myfunction original.conf my.conf

Non dimenticare i punti e virgola prima della parentesi quadra di destra. Allo stesso modo, per la vera domanda:

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

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

O:

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

3
Preferisco questa risposta, in quanto mostra una serie di argomenti che potrebbero presentarsi. $ 1 e $ 2 sono solo casi speciali, che è anche illustrato in questa risposta.
philo vivero,

16
Cambia mv "$1" "$1.bak"; cp "$2" "$1" in mv "$1" "$1.bak" && cp "$2" "$1"per non perdere i tuoi dati quando mvsi verificano problemi (ad esempio, il file system è pieno).
Henk Langeveld,

3
"Non dimenticare il punto e virgola prima della parentesi quadra di destra." Molte volte questo! Grazie :)
Kaushal Modi,

E sono richiesti anche gli spazi dopo la prima parentesi e prima dell'ultima parentesi.
Bryan Chapel,

1
@HenkLangeveld Sebbene la tua osservazione sia perfettamente corretta, mostra che sei stato in giro per un po '- Non saprei quando ho riscontrato un errore "spazio vuoto sul dispositivo" l'ultima volta ;-). (Lo uso regolarmente anche se non trovo più spazio sul bancone della cucina!) Non sembra succedere molto spesso in questi giorni.
Peter - Ripristina Monica il

124

La domanda viene semplicemente posta male. Non si crea un alias che accetta parametri perché aliasaggiunge solo un secondo nome per qualcosa che esiste già. La funzionalità richiesta dall'OP è il functioncomando per creare una nuova funzione. Non è necessario alias la funzione poiché la funzione ha già un nome.

Penso che tu voglia qualcosa del genere:

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

Questo è tutto! Puoi utilizzare i parametri $ 1, $ 2, $ 3, ecc. Oppure riempirli tutti con $ @


7
Questa risposta dice tutto. Se avessi letto dal fondo di questa pagina, avrei risparmiato un po 'di tempo.
Joe,

-1 Un alias e una funzione non sono equivalenti ...echo -e '#!/bin/bash\nshopt -s expand_aliases\nalias asrc='\''echo "${BASH_SOURCE[0]}"'\'' # note the '\''s\nfunction fsrc(){ echo "${BASH_SOURCE[0]}";}'>>file2&&echo -e '#!/bin/bash\n. file2\nalias rl='\''readlink -f'\''\nrl $(asrc)\nrl $(fsrc)'>>file1&&chmod +x file1&&./file1;rm -f file1 file2
Fuzzy Logic

Dovresti davvero citare $@per supportare i nomi dei file con spazi, ecc.
Tom Hale,

Doveva essere una spiegazione generale che non si hanno parametri alias, si usa invece una funzione. La funzione fornita era solo un esempio per contrastare l'esempio originale. Non penso che la persona stesse cercando una funzione di cestino per scopi generici. Tuttavia, nell'interesse di presentare un codice migliore, ho aggiornato la risposta.
Evan Langlois,

1
@FuzzyLogic - Ho impiegato qualche minuto a cercare di decomprimere il codice nel tuo commento. È un grande sforzo (interessante) da compiere per impacchettare del codice in un commento in cui non è possibile formattarlo correttamente. Non ho ancora capito esattamente cosa fa o, soprattutto, perché supporta la tua (corretta) affermazione.
Joe,

110

TL; DR: fai questo invece

È molto più facile e più leggibile usare una funzione che un alias per mettere gli argomenti nel mezzo di un comando.

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

Se continui a leggere, imparerai cose che non devi sapere sull'elaborazione degli argomenti della shell. La conoscenza è pericolosa Ottieni solo il risultato che desideri, prima che il lato oscuro controlli per sempre il tuo destino.

Una precisazione

bashalias fanno accettare argomenti, ma solo alla fine :

$ alias speak=echo
$ speak hello world
hello world

Mettere argomenti nel mezzo del comando tramite aliasè davvero possibile ma diventa brutto.

Non provarlo a casa, bambini!

Se ti piace eludere i limiti e fare ciò che gli altri dicono è impossibile, ecco la ricetta. Basta non incolparmi se i tuoi capelli si logorano e il tuo viso finisce coperto di fuliggine nello stile di uno scienziato pazzo.

La soluzione alternativa è passare gli argomenti che aliasaccettano solo alla fine a un wrapper che li inserirà nel mezzo e quindi eseguirà il comando.

Soluzione 1

Se sei davvero contrario all'utilizzo di una funzione in sé, puoi usare:

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

È possibile sostituire $@con $1se si desidera solo il primo argomento.

Spiegazione 1

Questo crea una funzione temporanea f, a cui vengono passati gli argomenti (nota che fviene chiamata alla fine). Il unset -frimuove la definizione di funzione come alias viene eseguito in modo da non rimanere in giro dopo.

Soluzione 2

Puoi anche usare una subshell:

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

Spiegazione 2

L'alias crea un comando come:

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

Commenti:

  • _È richiesto il segnaposto , ma potrebbe essere qualsiasi cosa. Viene impostato su sh's $0ed è necessario in modo che il primo degli argomenti forniti dall'utente non venga consumato. Dimostrazione:

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
  • Le virgolette singole sono racchiuse tra virgolette singole. Ecco un esempio che non funziona con le doppie virgolette:

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

    Qui i valori della shell interattiva $0e $@vengono sostituiti nel doppio tra virgolette prima che venga passato sh. Ecco la prova:

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

    Le virgolette singole assicurano che queste variabili non vengano interpretate dalla shell interattiva e vengano passate letteralmente a sh -c.

    Potresti usare le virgolette doppie e \$@, ma la migliore pratica è quella di citare i tuoi argomenti (in quanto potrebbero contenere spazi) e \"\$@\"sembra ancora più brutta, ma può aiutarti a vincere un concorso di offuscamento in cui i capelli lisci sono un prerequisito per l'ingresso.


2
per la soluzione 1, assicurati di utilizzare le virgolette singole ed evita \ "tra $ @. Una tecnica molto utile se ne hai bisogno. ty.
sgtz

La soluzione 1 ha funzionato per me racchiudere rdesktop-vrdp con argomenti per ogni server che desidero.
Hsehdar,

Accettare gli argomenti alla fine è esattamente ciò di cui avevo bisogno per sostituire "git checkout {branchname}" con un semplice "gc {branchname}". In .bash_profile ho semplicemente aggiuntoalias gc='git checkout'
AbstractVoid

@sgtz perché dovresti voler rimuovere le virgolette $@? Sono necessari se ad esempio sono presenti file con spazi.
Tom Hale,

@TomHale Questo è un po 'linguistico, ma la soluzione 1 non è davvero utile se qualcuno è davvero contrario all'utilizzo di una funzione (qualunque sia la ragione che potrebbe esserci) poiché dopo aver ammesso te stesso che stai solo spostando la definizione di una funzione al tempo di esecuzione di l'alias. in secondo luogo, "gli alias bash accettano argomenti, ma solo alla fine" è più semantica: gli alias sono per definizione sostituzioni di parole con stringhe. non devono accettare argomenti, ma i comandi che vengono eseguiti tramite la sostituzione possono farlo. alias è una sostituzione del personaggio, niente di più, niente di meno. no?
BUFU,

39

Una soluzione alternativa consiste nell'utilizzare marker , uno strumento che ho creato di recente che consente di "contrassegnare" i modelli di comando e posizionare facilmente il cursore sui segnaposto dei comandi:

indicatore della riga di comando

Ho scoperto che la maggior parte delle volte, sto usando le funzioni della shell, quindi non devo scrivere più e più volte comandi nella riga di comando. Il problema dell'utilizzo delle funzioni per questo caso d'uso è l'aggiunta di nuovi termini al mio vocabolario di comando e la necessità di ricordare a quali parametri delle funzioni si riferiscono nel comando reale. L'obiettivo del marcatore è quello di eliminare quel carico mentale.


14

Tutto quello che devi fare è creare una funzione all'interno di un alias:

$ alias mkcd='_mkcd(){ mkdir "$1"; cd "$1";}; _mkcd'

È necessario mettere doppie virgolette "$ 1" perché le virgolette singole non funzioneranno.


5
È intelligente, ma a parte il fatto che la domanda ha specificato di creare un alias, c'è qualche motivo per non fare inizialmente la funzione con lo stesso nome dell'alias?
xaxxon,

1
@xaxxon Non proprio, ma è il modo più semplice che conosco per usare un alias, non una funzione.
Ken Tran,

1
Questo non funziona. Su Ubuntu 18, ricevo un errore bash: syntax error near unexpected token '{mkdir'.
Shital Shah,

manca un trascinamento ;all'interno della funzione _mkcdmolto probabilmente l'errore deriva da quello.
Jetchisel il

Lascia spazio prima e dopo {e}
hesham_EE il

10

Ecco tre esempi di funzioni che ho nel mio ~/.bashrc, che sono essenzialmente alias che accettano un parametro:

#Utility required by all below functions.
#/programming/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://stackoverflow.com/a/3232082/2736496
    - Alias w/param: https://stackoverflow.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://stackoverflow.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
}

Riferimenti:


Eh? Questa è una funzione, non un alias. E uno dei tuoi riferimenti è proprio questa domanda.
triplo il

2
No, funziona esattamente come una funzione. Come molte delle risposte qui spiegano, non è possibile creare un alias che accetta un parametro. Quello che puoi fare è scrivere una funzione, che è ciò che hai fatto.
triplo il

1
@tripleee Dal mio punto di vista principiante, prima di leggere il tuo commento, ho pensato che fosse un alias (un modo alternativo per crearne uno). Funziona esattamente come uno, per quanto ne so. È essenzialmente un alias che accetta un parametro, anche se sono fuori dalla terminologia. Non vedo il problema. Ho chiarito il collegamento con l'altra risposta in questo problema. Mi ha aiutato a creare questo.
aliteralmind,

1
Forse questo non risponde specificamente alla domanda di "un alias bash che accetta un parametro", perché ora capisco che non è possibile, ma sicuramente risponde efficacemente . Cosa mi sto perdendo qui?
aliteralmind

2
Alcuni esempi davvero validi qui e codice ben commentato. Un grande aiuto per le persone che vengono su questa pagina.
Chim

9

Alias ​​Bash accetta assolutamente parametri. Ho appena aggiunto un alias per creare una nuova app di reazione che accetta il nome dell'app come parametro. Ecco il mio processo:

Apri il bash_profile per la modifica in nano

nano /.bash_profile

Aggiungi i tuoi alias, uno per riga:

alias gita='git add .'
alias gitc='git commit -m "$@"'
alias gitpom='git push origin master'
alias creact='npx create-react-app "$@"'

nota: "$ @" accetta i parametri passati come "creact my-new-app"

Salva ed esci da nano editor

ctrl + o to per scrivere (premi invio); ctrl + x per uscire

Di 'al terminale di usare i nuovi alias in .bash_profile

source /.bash_profile

Questo è tutto! Ora puoi usare i tuoi nuovi alias


6

NB: Nel caso in cui l'idea non sia ovvia, è una cattiva idea usare gli alias per tutto tranne che per gli alias, il primo è la "funzione in un alias" e il secondo è il "reindirizzamento / sorgente" difficile da leggere. Inoltre, ci sono difetti (che ho pensato fossero ovvi, ma nel caso in cui tu sia confuso: non intendo che siano effettivamente utilizzati ... ovunque!)

.................................................. .................................................. ............................................

Ho già risposto a questa domanda ed è sempre stato così in passato:

alias foo='__foo() { unset -f $0; echo "arg1 for foo=$1"; }; __foo()'

che va bene e bene, a meno che tu non stia evitando l'uso delle funzioni tutti insieme. nel qual caso puoi sfruttare la vasta capacità di bash di reindirizzare il testo:

alias bar='cat <<< '\''echo arg1 for bar=$1'\'' | source /dev/stdin'

Sono entrambi della stessa lunghezza che danno o prendono pochi personaggi.

Il vero kicker è la differenza di tempo, la parte superiore è il "metodo di funzione" e la parte inferiore è il "metodo di reindirizzamento". Per provare questa teoria, i tempi parlano da soli:

arg1 for foo=FOOVALUE
 real 0m0.011s user 0m0.004s sys 0m0.008s  # <--time spent in foo
 real 0m0.000s user 0m0.000s sys 0m0.000s  # <--time spent in bar
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.010s user 0m0.004s sys 0m0.004s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.011s user 0m0.000s sys 0m0.012s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.012s user 0m0.004s sys 0m0.004s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.010s user 0m0.008s sys 0m0.004s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE

Questa è la parte inferiore di circa 200 risultati, eseguiti a intervalli casuali. Sembra che la creazione / distruzione delle funzioni richieda più tempo del reindirizzamento. Spero che questo possa aiutare i futuri visitatori a questa domanda (non volevo tenerlo per me).


2
Avere un alias che definisce una funzione, quindi eseguire quella funzione è semplicemente stupido. Scrivi una funzione. Per quasi tutti gli scopi, gli alias sono sostituiti da funzioni shell.
geirha,

nel caso in cui non avessi letto tutto, cosa che potresti provare, stavo illustrando perché l'uso del metodo di funzione non era affatto buono in primo luogo, e inoltre, non è affatto sciocco. Smetti di pubblicare e sottoporre a votazioni solo perché non ti è piaciuto personalmente ... o almeno dare una spiegazione valida. La vocazione è il primo segno di
intimità

1
Il secondo (l'alias della barra) ha diversi effetti collaterali. Innanzitutto il comando non può usare stdin. In secondo luogo, se non viene fornito alcun argomento dopo l'alias, viene passato qualsiasi argomento della shell. L'uso di una funzione evita tutti questi effetti collaterali. (Anche l'uso inutile di gatto).
geirha,

2
ehi non ho mai detto che fosse una buona idea fare tutto questo, ho solo detto che c'erano anche altri modi per farlo - l'idea principale qui è che non dovresti usare le funzioni negli alias perché sono più lente di un complicato reindirizzamento, ho pensato che sarebbe stato ovvio, ma credo di doverlo precisare per tutti (che mi viene anche urlato perché il post è troppo gonfio se lo facessi in primo luogo)
osirisgothra

1
Dato che i tempi della barra sono tutti 0, sospetto che la shell non stia pianificando correttamente. Notare che il messaggio orario viene stampato prima dell'esecuzione del comando? Ergo, non fa nulla e quindi esegue la barra, quindi non si misura affatto la barra. Fai qualcosa di più complesso, o un grande loop nella barra in modo da poter rendere più ovvio che non stai programmando nulla
Evan Langlois,

6

Se stai cercando un modo generico per applicare tutti i parametri a una funzione, non solo uno o due o qualche altro importo hardcoded, puoi farlo in questo modo:

#!/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;

Quindi nell'esempio sopra, passo tutti i parametri da quando corro runjarall'alias.

Ad esempio, se lo facessi runjar hi therefinirebbe effettivamente per funzionare java -jar myjar.jar hi there. Se lo facessi runjar one two threecorrerebbe java -jar myjar.jar one two three.

Mi piace questa $@soluzione basata su perché funziona con qualsiasi numero di parametri.


4
perché non semplicemente nominare la funzione runjarinvece di renderla un alias di una funzione? Sembra inutilmente complicato!
Evan Langlois,

Le funzioni di @EvanLanglois sono automaticamente alias(o con le proprietà delle cose passate a alias) nei file bash? se sì, è solo il mio non averlo saputo
Michea il

Non capisco cosa intendi. Un alias è un altro nome, sia esso una persona o una funzione. Quindi, hai creato una funzione, quindi hai creato un secondo nome per la funzione. Non c'è niente di speciale nell'alias, è solo un secondo nome e non è richiesto. Ciò che digiti nella riga di comando può essere funzioni interne o esterne, quindi "function" esegue un nuovo comando, non alias.
Evan Langlois,

4
Questo è inutile. È lo stesso di alias runjar='java -jar myjar.jar'. Gli alias accettano argomenti, ma solo alla fine.
Tom Hale,

6

Rispettosamente a tutti coloro che dicono che non è possibile inserire un parametro nel mezzo di un alias, l'ho appena testato e ho scoperto che funzionava.

alias mycommand = "python3" $ 1 "script.py --folderoutput RISULTATI /"

quando ho quindi eseguito il comando foobar ha funzionato esattamente come se avessi digitato a lungo il comando.


Assolutamente, alias può ottenere parametri, sto usando questa età per es .: alias commit = "git commit -m $ 1"
agapitocandemor

Non funziona per me: mi alias myalias="echo 1 "$1" 3"; myalias 2dà:1 3 2
dirdi

4

Vi sono motivi tecnici legittimi per volere una soluzione generalizzata al problema dell'alias bash che non dispone di un meccanismo per accettare un riposizionamento di argomenti arbitrari. Uno dei motivi è se il comando che si desidera eseguire sarebbe influenzato negativamente dalle modifiche all'ambiente risultanti dall'esecuzione di una funzione. In tutti gli altri casi, è necessario utilizzare le funzioni.

Ciò che recentemente mi ha spinto a tentare una soluzione a questo è che volevo creare alcuni comandi abbreviati per stampare le definizioni di variabili e funzioni. Quindi ho scritto alcune funzioni a tale scopo. Tuttavia, ci sono alcune variabili che sono (o possono essere) modificate da una chiamata di funzione stessa. Tra questi ci sono:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

Il comando di base che stavo usando (in una funzione) per stampare i parametri variabili. nel modulo l'output del comando set era:

sv () { set | grep --color=never -- "^$1=.*"; }

Per esempio:

> V=voodoo
sv V
V=voodoo

Problema: questo non stampa le definizioni delle variabili sopra menzionate così come sono nel contesto corrente , ad esempio, se in un prompt interattivo della shell (o meno in qualsiasi chiamata di funzione), FUNCNAME non è definito. Ma la mia funzione mi dice informazioni sbagliate:

> sv FUNCNAME
FUNCNAME=([0]="sv")

Una soluzione che ho trovato è stata citata da altri in altri post su questo argomento. Per questo comando specifico per stampare variabili defn. E che richiede solo un argomento, ho fatto questo:

alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'

Che fornisce l'output corretto (nessuno) e lo stato del risultato (falso):

> asv FUNCNAME
> echo $?
1

Tuttavia, mi sentivo comunque obbligato a trovare una soluzione che funzionasse per un numero arbitrario di argomenti.

Una soluzione generale per passare argomenti arbitrari a un comando con alias Bash:

# (I put this code in a file "alias-arg.sh"):

# cmd [arg1 ...] – an experimental command that optionally takes args,
# which are printed as "cmd(arg1 ...)"
#
# Also sets global variable "CMD_DONE" to "true".
#
cmd () { echo "cmd($@)"; declare -g CMD_DONE=true; }

# Now set up an alias "ac2" that passes to cmd two arguments placed
# after the alias, but passes them to cmd with their order reversed:
#
# ac2 cmd_arg2 cmd_arg1 – calls "cmd" as: "cmd cmd_arg1 cmd_arg2"
#
alias ac2='
    # Set up cmd to be execed after f() finishes:
    #
    trap '\''cmd "${CMD_ARGV[1]}" "${CMD_ARGV[0]}"'\'' SIGUSR1;
    #        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    #       (^This is the actually execed command^)
    #
    # f [arg0 arg1 ...] – acquires args and sets up trap to run cmd:
    f () {
        declare -ag CMD_ARGV=("$@");  # array to give args to cmd
        kill -SIGUSR1 $$;             # this causes cmd to be run
        trap SIGUSR1;                 # unset the trap for SIGUSR1
        unset CMD_ARGV;               # clean up env...
        unset f;                      # incl. this function!
    };
    f'  # Finally, exec f, which will receive the args following "ac2".

Per esempio:

> . alias-arg.sh
> ac2 one two
cmd(two one)
>
> # Check to see that command run via trap affects this environment:
> asv CMD_DONE
CMD_DONE=true

Una cosa bella di questa soluzione è che tutti i trucchi speciali usati per gestire i parametri posizionali (argomenti) ai comandi funzioneranno durante la composizione del comando intercettato. L'unica differenza è che deve essere utilizzata la sintassi dell'array.

Per esempio,

Se vuoi "$ @", usa "$ {CMD_ARGV [@]}".

Se vuoi "$ #", usa "$ {# CMD_ARGV [@]}".

Eccetera.


3

Una volta ho fatto qualche progetto divertente e lo uso ancora. Sta mostrando alcune animazioni mentre copio i file tramite il cpcomando cpperché non mostrano nulla ed è abbastanza frustrante. Quindi ho creato questo alias

alias cp="~/SCR/spiner cp"

E questo è lo script spiner

#!/bin/bash

#Set timer
T=$(date +%s)

#Add some color
. ~/SCR/color

#Animation sprites
sprite=( "(* )  ( *)" " (* )( *) " " ( *)(* ) " "( *)  (* )" "(* )  ( *)" )

#Print empty line and hide cursor
printf "\n${COF}"

#Exit function
function bye { printf "${CON}"; [ -e /proc/$pid ] && kill -9 $pid; exit; }; trap bye INT

#Run our command and get its pid
"$@" & pid=$!

#Waiting animation
i=0; while [ -e /proc/$pid ]; do sleep 0.1

    printf "\r${GRN}Please wait... ${YLW}${sprite[$i]}${DEF}"
    ((i++)); [[ $i = ${#sprite[@]} ]] && i=0

done

#Print time and exit
T=$(($(date +%s)-$T))
printf "\n\nTime taken: $(date -u -d @${T} +'%T')\n"

bye

È così

inserisci qui la descrizione dell'immagine

Animazione ciclica)

inserisci qui la descrizione dell'immagine


2

Per prendere i parametri, dovresti usare le funzioni!

Tuttavia, $ @ viene interpretato durante la creazione dell'alias anziché durante l'esecuzione dell'alias e la escape di $ non funziona neanche. Come posso risolvere questo problema?

È necessario utilizzare la funzione shell anziché un alias per eliminare questo problema. Puoi definire foo come segue:

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

O

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

Infine, chiama il tuo foo () usando la sintassi seguente:

foo arg1 arg2 argN

Assicurati di aggiungere il tuo foo () a ~/.bash_profileo~/.zshrc file.

Nel tuo caso, questo funzionerà

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

Non capisco la tua idea. Penso che non sia importante quando gli argomenti vengono interpretati. Aliase accetta tutti i parametri che vuoi alla fine.
Timo,

Ma è meglio farlo con le funzioni. Gli alias non sono fatti per questo.
Ahmad Awais,

1

Le funzioni sono quasi sempre la risposta, come già ampiamente contribuito e confermato da questa citazione dalla pagina man: "Per quasi tutti gli scopi, gli alias sono sostituiti da funzioni shell".

Per completezza e poiché ciò può essere utile (sintassi leggermente più leggera), si può notare che quando i parametri seguono l'alias, possono ancora essere utilizzati (anche se questo non risponderebbe ai requisiti del PO). Questo è probabilmente il più semplice da dimostrare con un esempio:

alias ssh_disc='ssh -O stop'

mi permette di digitare smth come ssh_disc myhost, che si espande come previsto come:ssh -O stop myhost

Questo può essere utile per comandi che accettano argomenti complessi (la mia memoria non è più quella che usa per essere ...)


1

Sia le funzioni che gli alias possono utilizzare i parametri come altri hanno mostrato qui. Inoltre, vorrei sottolineare un paio di altri aspetti:

1. La funzione viene eseguita nel proprio ambito, alias condivide l'ambito

Potrebbe essere utile conoscere questa differenza nei casi in cui è necessario nascondere o esporre qualcosa. Suggerisce anche che una funzione è la scelta migliore per l'incapsulamento.

function tfunc(){
    GlobalFromFunc="Global From Func" # Function set global variable by default
    local FromFunc="onetwothree from func" # Set a local variable

}

alias talias='local LocalFromAlias="Local from Alias";  GlobalFromAlias="Global From Alias" # Cant hide a variable with local here '
# Test variables set by tfunc
tfunc # call tfunc
echo $GlobalFromFunc # This is visible
echo $LocalFromFunc # This is not visible
# Test variables set by talias
# call talias
talias
echo $GlobalFromAlias # This is invisible
echo $LocalFromAlias # This variable is unset and unusable 

Produzione:

bash-3.2$     # Test variables set by tfunc
bash-3.2$     tfunc # call tfunc
bash-3.2$     echo $GlobalFromFunc # This is visible
Global From Func
bash-3.2$     echo $LocalFromFunc # This is not visible

bash-3.2$     # Test variables set by talias
bash-3.2$     # call talias
bash-3.2$     talias
bash: local: can only be used in a function
bash-3.2$     echo $GlobalFromAlias # This is invisible
Global From Alias
bash-3.2$ echo $LocalFromAlias # This variable is unset and unusable

2. lo script wrapper è una scelta migliore

Mi è capitato più volte che non è possibile trovare un alias o una funzione quando si accede tramitessh o implica il cambio di nomi utente o ambiente multiutente. Ci sono trucchi e suggerimenti con i file dot di sourcing o questo interessante con alias: alias sd='sudo 'consente a questo alias successivo di alias install='sd apt-get install'funzionare come previsto (notare lo spazio aggiuntivo in ) quindi la funzione non è più visibile. Quindi, in caso di dubbio, uno script wrapper è sempre la soluzione più affidabile e portatile.sd='sudo ' ). Tuttavia, uno script wrapper funziona meglio di una funzione o di un alias in casi come questo. Il vantaggio principale con uno script wrapper è che è visibile / eseguibile per il percorso previsto (ovvero / usr / loca / bin /) dove come funzione / alias deve essere reperito prima che sia utilizzabile. Ad esempio, si inserisce una funzione in ~ / .bash_profile o ~ / .bashrc per bash, ma in seguito si passa a un'altra shell (ad es.zsh


1
Perché pensi che la versione della funzione non funzioni?
tripla il

@tripleee. Ho modificato il post per renderlo più leggibile. Sotto l'intestazione "1. alias works, function ..." ho illustrato perché una versione di funzione non funziona. E forse per rispondere direttamente alla domanda, la funzione introduce un nuovo ambito in cui l'alias no.
biocyberman,

Dici che non funziona ma non ti credo. sourcein una funzione funziona bene.
Tripleee

1
f () { source /tmp/nst; }fa esattamente quello che mi aspetto. Forse hai PATHtorto, quindi corre lo stesso activateo qualcosa del genere; ma l'esecuzione sourceda una funzione funziona bene.
Tripleee

1
A proposito, ri: usando la functionparola chiave nella tua definizione, vedi wiki.bash-hackers.org/scripting/obsolete - function funcname {è l'antica sintassi ksh bash supporta la retrocompatibilità con le shell pre-POSIX, mentre funcname() {è la sintassi standardizzata POSIX ufficiale. function funcname() {è una discrepanza tra i due che non è compatibile con l'antica ksh o compatibile con POSIX sh e che quindi è meglio evitare.
Charles Duffy,

1

Ecco l'esempio:

alias gcommit='function _f() { git add -A; git commit -m "$1"; } ; _f'

Molto importante:

  1. C'è uno spazio dopo {e prima }.
  2. C'è un ;dopo ogni comando in sequenza. Se lo dimentichi dopo l'ultimo comando, visualizzerai >invece il prompt!
  3. L'argomento è racchiuso tra virgolette "$1"

2
Non è necessario creare un alias per una funzione, basta usare la funzione direttamente.
user3439894

1

Come è già stato sottolineato da altri, l'uso di una funzione dovrebbe essere considerato la migliore pratica.

Tuttavia, ecco un altro approccio, sfruttando xargs:

alias junk="xargs -I "{}" -- mv "{}" "~/.Trash" <<< "

Si noti che ciò ha effetti collaterali sul reindirizzamento dei flussi.


0

Non devi fare nulla, alias lo fa automaticamente.

Ad esempio, se voglio rendere parametrizzato master origine git pull, posso semplicemente creare un alias come segue:

alias gpull = 'git pull origin '

e quando lo chiami effettivamente, puoi passare 'master' (il nome del ramo) come parametro, in questo modo:

gpull master
//or any other branch
gpull mybranch

Questo non risponde alla domanda, poiché l'argomento non può essere inserito liberamente, ma solo alla fine.
dirdi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.