做一个Bash别名,需要一个参数?

我曾经使用CShell( csh ),它可以让你使一个参数的别名。 这个符号是类似的

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

在Bash中,这似乎不起作用。 鉴于Bash有许多有用的function,我会假设这一个已经实施,但我想知道如何。

Bash别名不直接接受参数。 你将不得不创build一个函数和别名。

alias不接受参数,但可以像一个别名一样调用一个函数。 例如:

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

顺便说一下,在.bashrc和其他文件中定义的Bash函数可以在您的shell中作为命令使用。 所以,比如你可以像这样调用早期的函数

 $ myfunction original.conf my.conf 

细化上面的答案,你可以得到一行语法,就像你可以用别名一样,这对于shell或者.bashrc文件中的ad-hoc定义更方便:

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

不要忘记右括号前的分号。 同样,对于实际的问题:

 csh% alias junk="mv \\!* ~/.Trash" bash$ junk() { mv "$@" ~/.Trash/; } 

要么:

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

这个问题只是被问到错误。 您不会创build一个带参数的别名,因为alias只会为已存在的内容添加第二个名称。 OP需要的function是创build新function的function命令。 您不需要别名function,因为该function已经有一个名称。

我想你想要这样的东西:

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

而已! 你可以使用参数$ 1,$ 2,$ 3等,或只是用$ @

TL; DR:做这个

使用函数比使用别名将参数置于命令的中间要容易和可读。

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

如果你继续阅读,你将学到一些你不需要了解的关于shell参数处理的知识。 知识是危险的。 只要得到你想要的结果,在黑暗的一面永远控制你的命运之前。

澄清

bash别名确实接受参数,但只在最后

 $ alias speak=echo $ speak hello world hello world 

通过alias将参数置于命令的中间确实是可能的,但是会变得很难看。

不要在家里试试这个小子!

如果你喜欢绕过限制,做别人所说的不可能的事情,这里是配方。 只要不要责怪我,如果你的头发变得疲惫不堪,你的脸上就会笼罩着烟尘疯狂的科学家风格。

解决方法是将alias仅在最后接受的parameter passing给将它们插入中间然后执行命令的包装器。

解决scheme1

如果你真的反对使用一个函数本身,你可以使用:

 $ alias wrap_args='f(){ echo before "$@" after; unset -ff; }; f' $ wrap_args xyz before xyz after 

如果您只想要第一个参数,您可以用$1replace$@

说明1

这创build了一个临时函数f ,它传递了参数(注意f在最后被调用)。 unset -f在别名被执行时删除函数定义,所以它不会在后面挂起。

解决scheme2

你也可以使用一个子shell:

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

说明2

别名构build一个命令,如:

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

注释:

  • 占位符_是必需的,但可以是任何东西。 它被设置为sh$0 ,并且是必需的,以便用户给定的第一个参数不会被消耗。 示范:

     sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble Consumed: alcohol Printing: drunken babble 
  • 单引号内的单引号是必需的。 下面是一个不使用双引号的例子:

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

    这里交互式shell的$0$@的值被传递给sh 之前被replace成双引号。 这是certificate:

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

    单引号确保这些variables不被交互式shell解释,而是直接传递给sh -c

    你可以使用双引号和\$@ ,但是最好的做法是引用你的论点(因为它们可能包含空格),而\"\$@\"看起来更丑陋,但是可能会帮助你赢得模糊的头发是进入的先决条件。

另一种解决scheme是使用标记 ,我最近创build的一个工具可以让你“命令”模板,并轻松地将光标放在命令占位符处:

命令行标记

我发现大多数时候,我正在使用shell函数,所以我不必一次又一次地在命令行中编写经常使用的命令。 在这个用例中使用函数的问题是为我的命令词汇表添加新的术语,并且必须记住实际命令中参数引用的function。 标记的目标是消除这种精神负担。

以下是我在~/.bashrc中的三个函数示例,它们本质上是接受参数的别名:

 #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 } 

参考文献:

  • 从string修剪空白: 如何从Bashvariables修剪空白?
  • 实际换行符: https //stackoverflow.com/a/4296147/2736496
  • 别名w / param: https : //stackoverflow.com/a/7131683/2736496 (在这个问题的另一个答案)
  • HISTIGNORE: https ://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash
  • 是/否提示: https //stackoverflow.com/a/3232082/2736496
  • 删除历史logging中的所有匹配项: https //unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
  • string为空/空: http : //tldp.org/LDP/abs/html/comparison-ops.html

注意:如果这个想法不明显,那么除别名之外别名都使用别名是一个坏主意,第一个是“别名中的函数”,第二个是“难以读取的redirect/源”。 此外,还有一些缺陷(我认为这些缺陷很明显,但是如果您感到困惑,我并不是说它们实际上可以在任何地方使用!)

………………………………………….. ………………………………………….. ……………………………………..

我以前回答过这个问题,过去一直如此:

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

这很好,除非你一起避免使用函数。 在这种情况下,您可以利用bash的巨大能力redirect文本:

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

他们都是一样的长度给或几个字符。

真正的踢球者是时间差,顶部是“function方法”,底部是“redirect源”方法。 为了certificate这个理论,时机本身就说明了这一点:

 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 

这是约200个结果的底部,随机间隔完成。 看来,function创build/销毁需要比redirect更多的时间。 希望这将有助于未来的访问者这个问题(不想保留自己)。

为了参数,你应该使用函数!

但是,在创build别名时,而不是在别名的执行过程中,$ @被解释,并且转义$也不起作用。 我如何解决这个问题?

你需要使用shell函数而不是别名来摆脱这个问题。 你可以如下定义foo:

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

要么

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

最后,使用下面的语法调用你的foo():

 foo arg1 arg2 argN 

确保你添加你的foo()到~/.bash_profile~/.zshrc文件。

在你的情况下,这将工作

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

如果你正在寻找一种通用的方法来将所有的参数应用于一个函数,而不是一个或两个或其他硬编码的数量,你可以这样做:

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

所以在上面的例子中,我将所有参数从我运行runjar到别名。

例如,如果我做runjar hi there最终会实际运行java -jar myjar.jar hi there 。 如果我runjar one two three它会运行java -jar myjar.jar one two three

我喜欢这个基于$@的解决scheme,因为它适用于任何数量的参数。

有一个合理的技术理由,希望得到一个通用的解决scheme来解决bash别名没有一个机制来重定位任意论点的问题。 一个原因是,如果您希望执行的命令会受到执行function导致的环境变化的不利影响。 在所有其他情况下,都应该使用函数。

最近迫使我试图解决这个问题的是我想创build一些缩写命令来打印variables和函数的定义。 所以我为此写了一些function。 但是,有一些variables是(或可能)被函数调用本身改变的。 其中有:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

我一直使用(在函数中)打印variablesdefns的基本命令。 在set命令输出的forms是:

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

例如:

 > V=voodoo sv V V=voodoo 

问题:这不会像当前上下文那样打印上面提到的variables的定义,例如,如果在交互式shell提示下(或者不在任何函数调用中),则不定义FUNCNAME。 但是我的function告诉我错误的信息:

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

我提出的一个解决scheme已经被其他人在这个主题上的其他职位提到过。 对于这个特定的命令来打印variablesdefns。,而只需要一个参数,我做到了这一点:

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

其中给出正确的输出(无)和结果状态(假):

 > asv FUNCNAME > echo $? 1 

但是,我仍然不得不寻找一个适用于任意数量参数的解决scheme。

将任意parameter passing给Bash别名命令的一般解决scheme:

 # (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". 

例如:

 > . 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 

这个解决scheme的一个好处是,在编写trapped命令时,用于处理命令的位置参数(参数)的所有特殊技巧都将起作用。 唯一的区别是必须使用数组语法。

例如,

如果你想要“$ @”,使用“$ {CMD_ARGV [@]}”。

如果你想要“$#”,使用“$ {#CMD_ARGV [@]}”。

等等。

function确实几乎总是答案,已经充分的贡献,并从手册页的这个引用证实: “几乎所有的目的,别名被shell函数取代。

为了完整性,并且因为这可能是有用的(稍微更轻量级的语法),可以注意到,当参数跟随别名时,它们仍然可以被使用(尽pipe这不会解决OP的要求)。 这可能是最简单的例子:

 alias ssh_disc='ssh -O stop' 

允许我键入smth,如ssh_disc myhost ,它按照预期扩展,如下所示: ssh -O stop myhost

这对需要复杂参数的命令很有用(我的记忆不再是它所使用的东西)

但是,在.bashrc文件中创build别名时不需要使用函数。 例如

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

在.bashrc文件中进行更改后,确保input以下命令。

 ~$ source .bashrc 

你应该可以像这样使用它

 ~$ serve 8998