制作一个带参数的 Bash 别名?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7131670/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Make a Bash alias that takes a parameter?
提问by Hello
I used to use CShell (csh), which lets you make an alias that takes a parameter. The notation was something like
我曾经使用 CShell ( csh),它可以让您创建一个带有参数的别名。符号是这样的
alias junk="mv \!* ~/.Trash"
In Bash, this does not seem to work. Given that Bash has a multitude of useful features, I would assume that this one has been implemented but I am wondering how.
在 Bash 中,这似乎不起作用。鉴于 Bash 有许多有用的功能,我认为这个功能已经实现,但我想知道如何实现。
回答by arunkumar
Bash alias does not directly accept parameters. You will have to create a function.
Bash 别名不直接接受参数。您必须创建一个函数。
alias
does not accept parameters but a function can be called just like an alias. For example:
alias
不接受参数,但可以像别名一样调用函数。例如:
myfunction() {
#do things with parameters like such as
mv "" ".bak"
cp "" ""
}
myfunction old.conf new.conf #calls `myfunction`
By the way, Bash functions defined in your .bashrc
and other files are available as commands within your shell. So for instance you can call the earlier function like this
顺便说一下,在您的.bashrc
文件和其他文件中定义的 Bash 函数可作为 shell 中的命令使用。因此,例如您可以像这样调用较早的函数
$ myfunction original.conf my.conf
回答by Mike Gleason
Refining the answer above, you can get 1-line syntax like you can for aliases, which is more convenient for ad-hoc definitions in a shell or .bashrc files:
完善上面的答案,您可以获得像别名一样的 1 行语法,这对于 shell 或 .bashrc 文件中的临时定义更方便:
bash$ myfunction() { mv "" ".bak" && cp -i "" ""; }
bash$ myfunction original.conf my.conf
Don't forget the semi-colon before the closing right-bracket. Similarly, for the actual question:
不要忘记右括号前的分号。同样,对于实际问题:
csh% alias junk="mv \!* ~/.Trash"
bash$ junk() { mv "$@" ~/.Trash/; }
Or:
或者:
bash$ junk() { for item in "$@" ; do echo "Trashing: $item" ; mv "$item" ~/.Trash/; done; }
回答by Evan Langlois
The question is simply asked wrong. You don't make an alias that takes parameters because alias
just adds a second name for something that already exists. The functionality the OP wants is the function
command to create a new function. You do not need to alias the function as the function already has a name.
这个问题只是问错了。您不会创建带有参数的别名,因为alias
只是为已经存在的内容添加第二个名称。OP 想要的功能是function
创建新功能的命令。您不需要为函数添加别名,因为该函数已有名称。
I think you want something like this :
我想你想要这样的东西:
function trash() { mv "$@" ~/.Trash; }
That's it! You can use parameters $1, $2, $3, etc, or just stuff them all with $@
就是这样!您可以使用参数 $1、$2、$3 等,或者只用 $@ 填充它们
回答by Tom Hale
TL;DR: Do this instead
TL;DR:改为这样做
Its far easier and more readable to use a function than an alias to put arguments in the middle of a command.
使用函数比使用别名将参数放在命令中间更容易和更易读。
$ wrap_args() { echo "before $@ after"; }
$ wrap_args 1 2 3
before 1 2 3 after
If you read on, you'll learn things that you don't need to know about shell argument processing. Knowledge is dangerous. Just get the outcome you want, before the dark side forever controls your destiny.
如果您继续阅读,您将了解有关 shell 参数处理的不需要了解的内容。知识是危险的。在黑暗面永远控制你的命运之前,得到你想要的结果。
Clarification
澄清
bash
aliases doaccept arguments, but only at the end:
bash
别名确实接受参数,但仅在最后:
$ alias speak=echo
$ speak hello world
hello world
Putting arguments into the middleof command via alias
is indeed possible but it gets ugly.
将参数放入命令中间alias
确实是可能的,但它变得丑陋。
Don't try this at home, kiddies!
不要在家里尝试这个,孩子们!
If you like circumventing limitations and doing what others say is impossible, here's the recipe. Just don't blame me if your hair gets frazzled and your face ends up covered in soot mad-scientist-style.
如果你喜欢规避限制并做别人说不可能的事情,这里是秘诀。如果你的头发变得疲惫不堪,你的脸最终被煤烟疯狂科学家式覆盖,请不要责怪我。
The workaround is to pass the arguments that alias
accepts only at the end to a wrapper that will insert them in the middle and then execute your command.
解决方法是将alias
仅在最后接受的参数传递给包装器,该包装器将它们插入中间,然后执行您的命令。
Solution 1
解决方案1
If you're really against using a function per se, you can use:
如果你真的反对使用函数本身,你可以使用:
$ alias wrap_args='f(){ echo before "$@" after; unset -f f; }; f'
$ wrap_args x y z
before x y z after
You can replace $@
with $1
if you only want the first argument.
如果您只想要第一个参数$@
,$1
则可以替换为。
Explanation 1
说明 1
This creates a temporary function f
, which is passed the arguments (note that f
is called at the very end). The unset -f
removes the function definition as the alias is executed so it doesn't hang around afterwards.
这将创建一个临时函数f
,该函数被传递参数(注意f
在最后调用)。在unset -f
执行别名时删除函数定义,因此它之后不会挂起。
Solution 2
解决方案2
You can also use a subshell:
您还可以使用子shell:
$ alias wrap_args='sh -c '\''echo before "$@" after'\'' _'
Explanation 2
说明二
The alias builds a command like:
别名构建一个命令,如:
sh -c 'echo before "$@" after' _
Comments:
注释:
The placeholder
_
is required, but it could be anything. It gets set tosh
's$0
, and is required so that the first of the user-given arguments don't get consumed. Demonstration:sh -c 'echo Consumed: "
" Printing: "$@"' alcohol drunken babble Consumed: alcohol Printing: drunken babble$ sh -c "echo Consumed:
Printing: $@" alcohol drunken babble Consumed: -bash Printing:echo "Consumed:
Printing: $@" Consumed: -bash Printing:sh -c 'echo Consumed: "
" Printing: "$@"' alcohol drunken babble Consumed: alcohol Printing: drunken babble$ sh -c "echo Consumed:
Printing: $@" alcohol drunken babble Consumed: -bash Printing:echo "Consumed:
Printing: $@" Consumed: -bash Printing:$ alias mkcd='_mkcd(){ mkdir ""; cd "";}; _mkcd'
The single-quotes inside single-quotes are required. Here's an example of it not working with double quotes:
#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'"
Here the values of the interactive shell's
$0
and$@
are replaced into the double quoted beforeit is passed tosh
. Here's proof::<<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 "" | 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 }
The single quotes ensure that these variables are not interpreted by interactive shell, and are passed literally to
sh -c
.You could use double-quotes and
\$@
, but best practice is to quote your arguments (as they may contain spaces), and\"\$@\"
looks even uglier, but may help you win an obfuscation contest where frazzled hair is a prerequisite for entry.
占位符
_
是必需的,但它可以是任何东西。它被设置为sh
's$0
,并且是必需的,以便不会消耗用户给定的第一个参数。示范::<<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 "" }
单引号内的单引号是必需的。这是它不适用于双引号的示例:
:<<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 "" | 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 }
这里交互式 shell 的
$0
和的值在传递给之前$@
被替换为双引号。这里有证据:sh
nano /.bash_profile
单引号确保这些变量不被交互式 shell 解释,并按字面传递给
sh -c
.您可以使用双引号 and
\$@
,但最佳做法是引用您的论点(因为它们可能包含空格),\"\$@\"
看起来更难看,但可能会帮助您赢得一场混淆比赛,在这种比赛中,卷曲的头发是参赛的先决条件。
回答by Amine Hajyoussef
An alternative solution is to use marker, a tool I've created recently that allows you to "bookmark" command templates and easily place cursor at command place-holders:
另一种解决方案是使用marker,这是我最近创建的一个工具,它允许您“标记”命令模板并轻松地将光标放在命令占位符上:
I found that most of time, I'm using shell functions so I don't have to write frequently used commands again and again in the command-line. The issue of using functions for this use case, is adding new terms to my command vocabulary and having to remember what functions parameters refer to in the real-command. Marker goal is to eliminate that mental burden.
我发现大部分时间,我都在使用 shell 函数,所以我不必在命令行中一遍又一遍地编写常用命令。在这个用例中使用函数的问题是在我的命令词汇表中添加新术语,并且必须记住实际命令中参数所指的函数。Marker 的目标是消除这种心理负担。
回答by Ken Tran
All you have to do is make a function inside an alias:
您所要做的就是在别名中创建一个函数:
alias gita='git add .'
alias gitc='git commit -m "$@"'
alias gitpom='git push origin master'
alias creact='npx create-react-app "$@"'
You mustput double quotes around "$1" because single quotes will not work.
您必须在 "$1" 周围加上双引号,因为单引号不起作用。
回答by aliteralmind
Here's are three examples of functions I have in my ~/.bashrc
, that are essentiallyaliases that accept a parameter:
下面是我在 my 中的三个函数示例~/.bashrc
,它们本质上是接受参数的别名:
source /.bash_profile
.
.
alias foo='__foo() { unset -f alias bar='cat <<< '\''echo arg1 for bar='\'' | source /dev/stdin'
; echo "arg1 for foo="; }; __foo()'
.
.
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
.
.
##代码##References:
参考:
- Trimming whitespace from strings:How to trim whitespace from a Bash variable?
- Actual line breaks:https://stackoverflow.com/a/4296147/2736496
- Alias w/param:https://stackoverflow.com/a/7131683/2736496(another answer in this question)
- HISTIGNORE:https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash
- Y/N prompt:https://stackoverflow.com/a/3232082/2736496
- Delete all matching items from history:https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
- Is string null/empty:http://tldp.org/LDP/abs/html/comparison-ops.html
- 从字符串中修剪空格:如何从 Bash 变量中修剪空格?
- 实际换行符:https : //stackoverflow.com/a/4296147/2736496
- 别名 w/param:https : //stackoverflow.com/a/7131683/2736496 (这个问题的另一个答案)
- 历史信息:https ://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash
- 是/否提示:https : //stackoverflow.com/a/3232082/2736496
- 从历史记录中删除所有匹配的项目:https : //unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
- 是字符串空/空:http : //tldp.org/LDP/abs/html/comparison-ops.html
回答by Billeh
Bash alias absolutely does accept parameters. I just added an alias to create a new react app which accepts the app name as a parameter. Here's my process:
Bash 别名绝对接受参数。我刚刚添加了一个别名来创建一个新的 React 应用程序,它接受应用程序名称作为参数。这是我的过程:
Open the bash_profile for editing in nano
在 nano 中打开 bash_profile 进行编辑
##代码##Add your aliases, one per line:
添加别名,每行一个:
##代码##note: the "$@" accepts parameters passed in like "creact my-new-app"
注意:“$@”接受传入的参数,如“创建我的新应用程序”
Save and exit nano editor
保存并退出纳米编辑器
ctrl+o to to write (hit enter); ctrl+x to exit
ctrl+o 写入(按回车键);ctrl+x 退出
Tell terminal to use the new aliases in .bash_profile
告诉终端使用 .bash_profile 中的新别名
##代码##That's it! You can now use your new aliases
就是这样!您现在可以使用新别名
回答by Nathaniel
Respectfully to all those saying you can't insert a parameter in the middle of an alias I just tested it and found that it did work.
尊重所有那些说你不能在别名中间插入参数的人,我刚刚测试了它并发现它确实有效。
alias mycommand = "python3 "$1" script.py --folderoutput RESULTS/"
别名 mycommand = "python3 "$1" script.py --folderoutput RESULTS/"
when I then ran mycommand foobar it worked exactly as if I had typed the command out longhand.
然后,当我运行 mycommand foobar 时,它的工作方式与我手写命令时完全一样。
回答by osirisgothra
NB: In case the idea isn't obvious, it is a bad idea to use aliases for anything but aliases, the first one being the 'function in an alias' and the second one being the 'hard to read redirect/source'. Also, there are flaws (which i thoughtwould be obvious, but just in case you are confused: I do not mean them to actually be used... anywhere!)
注意:如果这个想法不明显,除了别名之外的任何东西都使用别名是一个坏主意,第一个是“别名中的函数”,第二个是“难以阅读的重定向/源”。此外,也有缺陷(我认为这很明显,但以防万一你感到困惑:我并不是说它们实际上可以用于......任何地方!)
................................................................................................................................................
……………………………………………………………………………………………………………………………………………………………… ………………………………………………………………………………………………………………………………………………………… ………………………………………………………………………………………………………………………………………………………………………………
I've answered this before, and it has always been like this in the past:
这个我以前回答过,过去一直是这样:
##代码##which is fine and good, unless you are avoiding the use of functions all together. in which case you can take advantage of bash's vast ability to redirect text:
这很好,除非您避免同时使用函数。在这种情况下,您可以利用 bash 重定向文本的强大功能:
##代码##They are both about the same length give or take a few characters.
它们的长度大致相同,给或取几个字符。
The realkicker is the time difference, the top being the 'function method' and the bottom being the 'redirect-source' method. To prove this theory, the timing speaks for itself:
的真正起脚的时间差,顶部作为“函数法”和底部作为“重定向源”的方法。为了证明这一理论,时机不言自明:
##代码##This is the bottom part of about 200 results, done at random intervals. It seems that function creation/destruction takes more time than redirection. Hopefully this will help future visitors to this question (didn't want to keep it to myself).
这是大约 200 个结果的底部,以随机间隔完成。似乎函数创建/销毁比重定向花费更多的时间。希望这将有助于这个问题的未来访问者(不想把它留给我自己)。