#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
}
注意:如果想法不是't obvious, it is a bad idea to use aliases for anything but aliases, the first one being the '函数,别名' and the second one being the '难以阅读重定向/源” . 此外,还有一些缺陷(我认为这是显而易见的,但万一你会感到困惑:我并不是说它们实际上被用到了......任何地方!)
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
#!/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 .
A General Solution To Passing Arbitrary Arguments To A Bash Aliased Command:
# (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
function conda_activate(){
export PATH="$PATH:/path/to/conda"
# do some other things
}
alias conda_env='conda_activate; source activate'
# usage example
conda_env myenv
12 回答
Bash别名不直接接受参数 . 您将不得不创建一个函数和别名 .
alias
不接受参数,但可以像调用别名一样调用函数 . 例如:顺便说一句,
.bashrc
和其他文件中定义的Bash函数可作为shell中的命令使用 . 因此,例如,您可以像这样调用早期的函数改进上面的答案,您可以像使用别名一样获得单行语法,这对于shell或.bashrc文件中的临时定义更方便:
不要忘记关闭右括号前的分号 . 同样,对于实际问题:
要么:
这个问题简直被问到了错误 . 您没有创建带参数的别名,因为
alias
只为已存在的内容添加了第二个名称 . OP想要的功能是用于创建新功能的function
命令 . 您不需要为函数设置别名,因为函数已有名称 .我想你想要这样的东西:
而已!您可以使用参数$ 1,$ 2,$ 3等,或者只需将它们全部填入$ @
TL; DR:改为做
使用函数比使用别名将参数放在命令中间更容易和更易读 .
如果您继续阅读,您将学习关于shell参数处理不需要了解的内容 . 知识很危险 . 只要得到你想要的结果,在黑暗面永远控制你的命运之前 .
澄清
bash
别名接受参数,但仅限于结尾:通过
alias
将参数置于命令的中间确实是可能的,但它变得丑陋 .不要在家里尝试这个,小子!
如果您喜欢规避限制并做其他人认为不可能的事情,那么这就是配方 . 如果你的头发被弄得疲惫不堪,你的脸最终被烟灰色的科学家风格所覆盖,就不要怪我 .
解决方法是将
alias
仅在最后接受的参数传递给将在中间插入它们然后执行命令的包装器 .解决方案1
如果你真的反对使用函数本身,你可以使用:
如果您只想要第一个参数,可以用
$1
替换$@
.Explanation 1
这会创建一个临时函数
f
,它传递参数(注意在最后调用f
) .unset -f
在执行别名时删除了函数定义,因此之后不会挂起 .解决方案2
您还可以使用子shell:
Explanation 2
别名构建如下命令:
评论:
_
是必需的,但它可以是任何内容 . 它被设置为sh
的$0
,并且是必需的,以便第一个用户给定的参数不被消耗 . 示范:这里交互式shell的
$0
和$@
的值在传递给sh
之前被替换为双引号 . 这是证据:单引号确保交互式shell不解释这些变量,并按字面顺序传递给
sh -c
.您可以使用双引号和
\$@
,但最佳做法是引用您的参数(因为它们可能包含空格),并且\"\$@\"
看起来更加丑陋,但可能会帮助您赢得混淆比赛,其中疲惫的头发是进入的先决条件 .另一种解决方案是使用marker,这是我最近创建的一个工具,它允许您使用"bookmark"命令模板并轻松将光标放在命令占位符上:
我发现大部分时间,我都在使用shell函数,因此我不必在命令行中反复编写常用命令 . 在这个用例中使用函数的问题是在命令词汇表中添加新术语,并且必须记住在real-command中引用的函数参数 . 标记的目标是消除这种心理负担 .
以下是我在
~/.bashrc
中的三个函数示例,它们基本上是接受参数的别名:.
.
.
参考文献:
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(这个问题的另一个答案)
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
注意:如果想法不是't obvious, it is a bad idea to use aliases for anything but aliases, the first one being the '函数,别名' and the second one being the '难以阅读重定向/源” . 此外,还有一些缺陷(我认为这是显而易见的,但万一你会感到困惑:我并不是说它们实际上被用到了......任何地方!)
.................................................. .................................................. ............................................
我之前已经回答了这个问题,过去一直如此:
这是好的和好的,除非你一直避免使用功能 . 在这种情况下,您可以利用bash的重定向文本的巨大能力:
它们的长度大约相同,或者取几个字符 .
真正的踢球者是时差,顶部是'function method',底部是'redirect-source'方法 . 为证明这一理论,时机不言而喻:
这是大约200个结果的底部,以随机间隔完成 . 似乎函数创建/销毁比重定向花费更多时间 . 希望这将有助于未来的访问者提出这个问题(不想保留给自己) .
如果您正在寻找将所有参数应用于函数的通用方法,而不仅仅是一个或两个或其他一些硬编码量,您可以这样做:
所以在上面的例子中,我将所有参数从我运行
runjar
时传递给别名 .例如,如果我做
runjar hi there
,它最终会实际运行java -jar myjar.jar hi there
. 如果我做runjar one two three
它会运行java -jar myjar.jar one two three
.我喜欢这个基于
$@
的解决方案,因为它适用于任意数量的参数 .要获取参数,您应该使用函数!
但是,在创建别名而不是在执行别名期间解释$ @时,并且转义$也不起作用 . 我该如何解决这个问题?
您需要使用shell函数而不是别名来解决此问题 . 您可以按如下方式定义foo:
要么
最后,使用以下语法调用foo():
确保将foo()添加到
~/.bash_profile
或~/.zshrc
文件中 .在你的情况下,这将工作
有合理的技术理由要求对bash别名问题进行通用解决,而不是有一种机制来重新定位任意参数 . 一个原因是,如果您希望执行的命令会受到执行函数导致的环境更改的不利影响 . 在所有其他情况下,应使用函数 .
最近迫使我尝试解决这个问题的方法是,我想创建一些缩写命令来打印变量和函数的定义 . 所以我为此目的写了一些函数 . 但是,函数调用本身会(或可能)更改某些变量 . 其中包括:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
我一直在使用(在函数中)打印变量defns的基本命令 . 在set命令输出的表单中是:
例如 . :
问题:这不会打印上面提到的变量的定义,因为它们在当前上下文中,例如,如果在交互式shell提示符中(或者在任何函数调用中没有),则不定义FUNCNAME . 但我的功能告诉我错误的信息:
我提出的一个解决方案已被其他人在此主题的其他帖子中提及 . 对于这个打印变量defns的特定命令,并且只需要一个参数,我这样做了:
这给出了正确的输出(无)和结果状态(false):
但是,我仍然觉得有必要找到适用于任意数量参数的解决方案 .
A General Solution To Passing Arbitrary Arguments To A Bash Aliased Command:
例如 . :
这个解决方案的一个好处是,用于处理命令的位置参数(参数)的所有特殊技巧在编写陷阱命令时都会起作用 . 唯一的区别是必须使用数组语法 .
例如 . ,
如果你想要“$ @”,请使用“$ {CMD_ARGV [@]}” .
如果你想要“$#”,请使用“$ {#CMD_ARGV [@]}” .
等等 .
虽然功能通常是一个很好的选择,就像其他人在这里说的那样 . 但我想指出的是,有些情况下函数不起作用,别名,或者其他情况下,包装脚本是更好的选择 .
alias works, function doesn't, and one still can pass parameters.
例如:我想创建一个快捷方式来激活
conda
并在一个命令中获取conda环境 . 很有可能这样做:这不按预期工作 . 如果一个人跑了
conda_activate myenv
.source
命令执行源,但立即退出,并且正在运行的shell没有环境 .工作解决方案如下所示:
wrapper script is a better choice
我多次遇到过在通过
ssh
进行日志记录或涉及切换用户名或多用户环境时无法找到别名或函数的情况 . 有点源文件的提示和技巧,例如,这个有趣的一点:alias sd='sudo '
让这个alias install='sd apt-get install'
按预期工作 . 注意sd='sudo '
中的额外空格 . 但是当你有疑问时,包装脚本总是最可靠的便携式方案 .功能确实几乎总是答案,因为已经充分贡献并通过手册页中的引用证实:"For almost every purpose, aliases are superseded by shell functions."
为了完整性并且因为这可能是有用的(稍微更轻量级的语法),可以注意到当参数遵循别名时,它们仍然可以使用(尽管这不符合OP的要求) . 这可能是最简单的示例:
允许我输入类似于
ssh_disc myhost
的smth,它按预期扩展为:ssh -O stop myhost
这对于采用复杂参数的命令非常有用(我的内存不再是它的用途......)