Zrobić Alias Bash, który pobiera parametr?
Używałem CShell ( csh ), który pozwala na utworzenie aliasu, który pobiera parametr. Zapis był czymś w rodzaju
alias junk="mv \\!* ~/.Trash"
W Bash to nie działa. Biorąc pod uwagę, że Bash ma wiele przydatnych funkcji, zakładam, że ten został zaimplementowany, ale zastanawiam się, jak.
12 answers
Alias Bash nie akceptuje bezpośrednio parametrów. Będziesz musiał utworzyć funkcję i alias, że.
alias
nie akceptuje parametrów, ale funkcję można wywołać tak jak alias. Na przykład:
myfunction() {
#do things with parameters like $1 such as
mv "$1" "$1.bak"
cp "$2" "$1"
}
myfunction old.conf new.conf #calls `myfunction`
Nawiasem mówiąc, funkcje Bash zdefiniowane w .bashrc
i inne pliki są dostępne jako polecenia w powłoce. Na przykład możesz wywołać wcześniejszą funkcję w ten sposób
$ myfunction original.conf my.conf
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-12 16:02:49
Udoskonalając powyższą odpowiedź, można uzyskać składnię 1-liniową, jak można Dla aliasów, co jest wygodniejsze dla definicji ad-hoc w powłoce lub .pliki bashrc:
bash$ myfunction() { mv "$1" "$1.bak"; cp "$2" "$1"; }
bash$ myfunction original.conf my.conf
Nie zapomnij o dwukropku przed zamknięciem prawego wspornika. Podobnie, dla rzeczywistego pytania:
csh% alias junk="mv \\!* ~/.Trash"
bash$ junk() { mv "$@" ~/.Trash/; }
Lub:
bash$ junk() { for item in "$@" ; do echo "Trashing: $item" ; mv "$item" ~/.Trash/; done; }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-14 16:10:13
Pytanie jest po prostu zadawane źle. Nie tworzysz aliasu, który pobiera parametry, ponieważ alias
dodaje tylko drugą nazwę dla czegoś, co już istnieje. Funkcja, której chce OP, to polecenie function
do utworzenia nowej funkcji. Nie musisz alias funkcji, ponieważ funkcja ma już nazwę.
Myślę, że chcesz coś takiego:
function trash() { mv "$@" ~/.Trash; }
To jest to! Możesz użyć parametrów $1, $2, $3 itp., lub po prostu wypchnąć je wszystkie za pomocą $@Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-10 05:11:12
TL;DR: zrób to zamiast
Jest o wiele łatwiejsze i bardziej czytelne użycie funkcji niż aliasu do umieszczania argumentów w środku polecenia.
$ wrap_args() { echo "before $@ after"; }
$ wrap_args 1 2 3
before 1 2 3 after
Jeśli czytasz dalej, dowiesz się rzeczy, których nie musisz wiedzieć o przetwarzaniu argumentów powłoki. Wiedza jest niebezpieczna. Po prostu uzyskaj pożądany rezultat, zanim ciemna strona na zawsze zapanuje nad twoim przeznaczeniem.
Wyjaśnienie
bash
aliasy czy akceptują argumenty, ale tylko w end :
$ alias speak=echo
$ speak hello world
hello world
Umieszczanie argumentów wśrodku polecenia poprzez alias
jest rzeczywiście możliwe, ale robi się nieprzyjemnie.
Jeśli lubisz omijać ograniczenia i robić to, co inni mówią, że jest niemożliwe, oto przepis. Tylko nie obwiniaj mnie, jeśli twoje włosy się postrzępią, a twoja twarz będzie pokryta sadzą w stylu szalonego naukowca.
Obejściem jest przekazanie argumentów, które alias
akceptuje tylko na końcu do wrapper, który wstawia je w środku, a następnie wykonuje polecenie.
Rozwiązanie 1
Jeśli naprawdę jesteś przeciwny używaniu funkcji per se, możesz użyć:
$ alias wrap_args='f(){ echo before "$@" after; unset -f f; }; f'
$ wrap_args x y z
before x y z after
Możesz zamienić $@
na $1
jeśli chcesz tylko pierwszy argument.
Wyjaśnienie 1
Tworzy to tymczasową funkcję f
, która jest przekazywana argumentom (zauważ, że f
jest wywoływana na samym końcu). unset -f
usuwa definicję funkcji, ponieważ alias jest stracony, żeby potem nie zawisła.
Rozwiązanie 2
Możesz również użyć subshell:
$ alias wrap_args='sh -c '\''echo before "$@" after'\'' _'
Wyjaśnienie 2
Alias buduje polecenie w stylu:
sh -c 'echo before "$@" after' _
Komentarze:
-
Symbol zastępczy
_
jest wymagany, ale może to być cokolwiek. Jest on ustawiany nash
' S$0
i jest wymagany, aby pierwszy z podanych przez użytkownika argumentów nie został zużyty. Demonstracja:sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble Consumed: alcohol Printing: drunken babble
-
The pojedyncze cudzysłowy wewnątrz pojedynczych cudzysłowów są wymagane. Oto przykład tego, że nie działa z podwójnymi cudzysłowami: {]}
$ sh -c "echo Consumed: $0 Printing: $@" alcohol drunken babble Consumed: -bash Printing:
Tutaj wartości powłoki interaktywnej
$0
i {[11] } są zamieniane na podwójne cytowane , zanim zostanie przekazana dosh
. Oto dowód:echo "Consumed: $0 Printing: $@" Consumed: -bash Printing:
Pojedyncze cudzysłowy zapewniają, że te zmienne nie są interpretowane przez interaktywną powłokę i są przekazywane dosłownie do
sh -c
.Możesz użyć podwójnych cudzysłowów i
\$@
, ale najlepszą praktyką jest cytując twoje argumenty (ponieważ mogą zawierać spacje), i\"\$@\"
wygląda jeszcze brzydiej, ale może pomóc Ci wygrać konkurs zaciemniania, w którym frazzled hair jest warunkiem wstępnym do wpisu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 03:02:51
Alternatywnym rozwiązaniem jest użycie marker , narzędzia, które niedawno stworzyłem, które pozwala na "zakładkę" szablonów poleceń i łatwe umieszczanie kursora w posiadaczach poleceń:
Odkryłem, że przez większość czasu używam funkcji powłoki, więc nie muszę pisać często używanych poleceń w wierszu poleceń. Problem użycia funkcji w tym przypadku użycia polega na dodaniu nowych terminów do mojego słownika poleceń i konieczności zapamiętania, jakie parametry funkcji zobacz w poleceniu rzeczywistym. Celem markera jest wyeliminowanie tego obciążenia psychicznego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-22 13:24:24
Oto trzy przykłady funkcji, które mam w moim ~/.bashrc
, które są zasadniczo aliasami akceptującymi parametr:
#Utility required by all below functions.
#https://stackoverflow.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://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
}
Bibliografia:
- przycinanie białych znaków: Jak przyciąć białe znaki ze zmiennej Bash?
- rzeczywiste podziały linii: https://stackoverflow.com/a/4296147/2736496
- Alias w / param: https://stackoverflow.com/a/7131683/2736496 ( kolejna odpowiedź na to pytanie)
- HYSTIGNORE: https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash
- y/n prompt: https://stackoverflow.com/a/3232082/2736496
- Usuń wszystkie pasujące elementy z historii: https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
- jest ciągiem null/empty: http://tldp.org/LDP/abs/html/comparison-ops.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:03
NB: W przypadku, gdy pomysł nie jest oczywisty, to jest złym pomysłem, aby używać aliasów do wszystkiego, oprócz aliasów, pierwszy z nich jest "funkcja w aliasie", a drugi jest "trudne do odczytania przekierowanie / źródło". Ponadto, są wady (które myślałem byłoby oczywiste, ale na wypadek, gdybyś był zdezorientowany: nie mam na myśli, aby były rzeczywiście używane... gdziekolwiek!)
................................................................................................................................................
Odpowiadałem już na to wcześniej i zawsze tak było w przeszłości:
alias foo='__foo() { unset -f $0; echo "arg1 for foo=$1"; }; __foo()'
Co jest dobre i dobre, chyba że unikasz korzystania z funkcji razem. w takim przypadku możesz skorzystać z ogromnej zdolności Basha do przekierowywania tekstu:
alias bar='cat <<< '\''echo arg1 for bar=$1'\'' | source /dev/stdin'
Obie są mniej więcej tej samej długości kilka znaków.
The real kicker jest różnicą czasu, góra jest 'metodą funkcji', a dół jest 'metodą redirect-source'. Aby udowodnić tę teorię, czas mówi sam za siebie:
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
Jest to dolna część około 200 wyników, wykonanych w losowych odstępach czasu. Wydaje się, że tworzenie/niszczenie funkcji zajmuje więcej czasu niż przekierowanie. Mam nadzieję, że pomoże to przyszłym odwiedzającym to pytanie (nie chciałem zachować tego dla siebie).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-21 13:08:48
Do pobierania parametrów należy używać funkcji!
Jednak $ @ get interpretowane podczas tworzenia aliasu zamiast podczas wykonywania aliasu i ucieczki $ też nie działa. Jak rozwiązać ten problem?
Aby pozbyć się tego problemu, musisz użyć funkcji powłoki zamiast aliasu. Możesz zdefiniować foo w następujący sposób:
function foo() { /path/to/command "$@" ;}
Lub
foo() { /path/to/command "$@" ;}
Na koniec wywołaj Foo () używając następującej składni:
foo arg1 arg2 argN
Upewnij się, że dodałeś foo () do ~/.bash_profile
lub ~/.zshrc
plik.
W Twoim przypadku to zadziała
function trash() { mv $@ ~/.Trash; }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-28 09:15:37
Istnieją uzasadnione powody techniczne, aby chcieć uogólnionego rozwiązania problemu aliasu bash, który nie ma mechanizmu do zmiany pozycji arbitralnych argumentów. Jednym z powodów jest to, że polecenie, które chcesz wykonać, będzie miało negatywny wpływ na zmiany w środowisku, które wynikają z wykonania funkcji. We wszystkich innych należy używać funkcji.
To, co ostatnio zmusiło mnie do próby rozwiązania tego problemu, to to, że chciałem stworzyć kilka skrótów polecenia do drukowania definicji zmiennych i funkcji. Więc napisałem kilka funkcji w tym celu. Istnieją jednak pewne zmienne, które są (lub mogą być) zmieniane przez samo wywołanie funkcji. Wśród nich są:FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
Podstawowe polecenie, którego używałem (w funkcji) do wypisywania zmiennych defns. w postaci wyjście poleceniem set było:
sv () { set | grep --color=never -- "^$1=.*"; }
Np.:
> V=voodoo
sv V
V=voodoo
Problem: to nie wydrukuje definicje zmiennych wymienionych powyżej w bieżącym kontekście , np. jeśli w interaktywnym wierszu polecenia powłoki (lub nie w wywołaniu funkcji), FUNCNAME nie jest zdefiniowane. Ale moja funkcja mówi mi złe informacje:
> sv FUNCNAME
FUNCNAME=([0]="sv")
Jedno rozwiązanie, które wymyśliłem, zostało wspomniane przez innych w innych postach na ten temat. Dla tego konkretnego polecenia wypisuje zmienne defns. i co wymaga tylko jednego argumentu, zrobiłem to:
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
Który daje prawidłowe wyjście (none), and result status (false):
> asv FUNCNAME
> echo $?
1
Jednak nadal czułem się zmuszony do znalezienia rozwiązania, które działa dla dowolnej liczby argumentów.
Ogólne Rozwiązanie Przekazywania Dowolnych Argumentów Do Polecenia Aliased 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".
Np.:
> . 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
Miłą rzeczą w tym rozwiązaniu jest to, że wszystkie specjalne sztuczki używane do obsługi parametrów pozycyjnych (argumentów) poleceń będą działać podczas komponowania uwięzionego polecenia. Jedyną różnicą jest to, że należy użyć składni tablicy.
Np.,
Jeśli chcesz "$@", użyj " ${CMD_ARGV [@]}".
Jeśli chcesz "$#", użyj " ${#CMD_ARGV [@]}".
Itd.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-18 17:42:09
Jeśli szukasz ogólnego sposobu na zastosowanie wszystkich paramów do funkcji, a nie tylko jednej, dwóch lub innej twardo zakodowanej kwoty, możesz to zrobić w ten sposób:
#!/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;
W powyższym przykładzie przekazuję wszystkie parametry od uruchomienia runjar
do aliasu.
Na przykład, gdybym to zrobił {[2] } to skończyłoby się na uruchomieniu java -jar myjar.jar hi there
. Gdybym to zrobił, to by działało java -jar myjar.jar one two three
.
Podoba mi się to rozwiązanie oparte na $@
, ponieważ działa z dowolną liczbą paramów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-29 20:54:46
Funkcje są rzeczywiście prawie zawsze odpowiedzią, co zostało już potwierdzone cytatem ze strony podręcznika: " w prawie każdym celu aliasy są zastępowane przez funkcje powłoki."
Dla kompletności i ponieważ może to być użyteczne (nieco bardziej lekka składnia), można zauważyć, że Gdy parametr(y) podąża za aliasem, nadal mogą być używane (chociaż nie odpowiadałoby to wymaganiom OP). Jest to prawdopodobnie najłatwiejsze do wykazania za pomocą przykład:
alias ssh_disc='ssh -O stop'
Pozwala mi wpisać smth jak ssh_disc myhost
, który jest rozszerzany zgodnie z oczekiwaniami jak: ssh -O stop myhost
Może to być przydatne dla poleceń, które przyjmują złożone argumenty(moja pamięć nie jest już tym, czego używa t be...)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-19 10:19:18
Nie potrzebujesz jednak funkcji podczas tworzenia aliasów w pliku .bashrc
.
Na przykład
# create an alias that takes port-number by the user
alias serve="python -m SimpleHTTPServer $1"
Po dokonaniu zmiany w .plik bashrc, upewnij się, że wprowadzasz następujące polecenie.
~$ source .bashrc
Powinieneś być w stanie używać tego w ten sposób
~$ serve 8998
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-10 03:44:43