做一个带有参数的Bash别名?


1270

我曾经用过CShell(),这样您就可以创建一个带参数的别名。记号有点像

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

在Bash中,这似乎不起作用。鉴于Bash具有许多有用的功能,我想假设该功能已实现,但我想知道如何实现。



2
确保你周围使用ARGS报价"$1"
克里斯托夫•鲁西

对于SO,这个问题是题外话。它回答了UNIX.SE,得到的答复是,你甚至不需要理会:“举例来说,如果你要的别名lsls -la,然后打字ls foo bar真正执行ls -la foo bar。在命令行”
Dan Dascalescu

7
那将无助于将变量插值到字符串的中间
Franz Sittampalam '18

1
这是我用来发现这个谬误的lil测试别名... alias test_args="echo PREFIX --$1-- SUFFIX",当与调用时,会test_args ABCD产生以下控制台输出PREFIX ---- SUFFIX ABCD
jxramos

Answers:


2122

Bash别名不直接接受参数。您将必须创建一个函数。

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

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


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

顺便说一句,在您的.bashrc文件和其他文件中定义的Bash函数可作为外壳程序中的命令使用。因此,例如,您可以像这样调用早期的函数

$ myfunction original.conf my.conf

48
我应该$1用引号括起来吗?
尔根·保罗

263
您甚至不必声明别名。仅定义函数即可。
dinigo 2013年

206
如果您要为函数更改别名,则source.bashrc将添加该函数,但不会取消别名别名。由于别名比功能具有更高的先例,因此它将尝试使用别名。您需要关闭然后重新打开外壳程序,否则调用unalias <name>。也许我会在我刚刚浪费的5分钟内为某人节省时间。
马蒂·尼尔

55
@MartinNeal:我在Sun中学到的一种省时的技巧是exec bash:做一个:它将启动一个新的Shell,使您可以清晰地读取配置,就像关闭并重新打开一样,但也要保留该会话的环境变量设置。同样,bash当您要处理像栈一样的想法时,不使用exec进行执行也很有用。
Macneil Shonle 2014年

21
@mich-是的,始终将bash变量放在引号中。例如mv "$1" "$1.bak"。不带引号的情况下,如果$ 1是“ hello world”,则您将执行mv hello world hello world.bak而不是mv "hello world" "hello world.bak"
Orion elenzil 2015年

208

细化上面的答案,您可以获得类似于别名的一行语法,这对于shell或.bashrc文件中的临时定义更方便:

bash$ myfunction() { mv "$1" "$1.bak" && cp -i "$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; }

3
我更喜欢这个答案,因为它显示了遍历可能传入的参数数组。$ 1和$ 2只是特殊情况,在此答案中也有说明。
philo vivero 2014年

16
更改mv "$1" "$1.bak"; cp "$2" "$1"mv "$1" "$1.bak" && cp "$2" "$1"不丢失数据时mv遇到麻烦(例如,文件系统已满)。
Henk Langeveld '16

3
“别忘了右括号前的分号。” 很多次!谢谢:)
Kaushal Modi

并且第一个括号之后和最后一个括号之前的空格也是必需的。
布赖恩教堂

1
@HenkLangeveld虽然您的发言是完全正确的,但它表明您已经存在了一段时间-我不知道我上次遇到“设备上没有剩余空间”错误的问题;-)。(不过,当我在厨房的柜台上找不到更多的空间时,我会定期使用它!)这些天似乎很少发生。
彼得-恢复莫妮卡

124

这个问题只是被问错了。您不必创建一个带参数的别名,因为它alias只是为已经存在的名称添加第二个名称。OP想要的功能是function创建新功能的命令。您无需为函数加上别名,因为该函数已经具有名称。

我想你想要这样的东西:

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

而已!您可以使用参数$ 1,$ 2,$ 3等,也可以只用$ @填充它们


7
这个答案说明了一切。如果我从本页底部开始阅读,那我已经节省了一些时间。

-1别名和函数不等效...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
模糊逻辑

你真的应该引用$@来支持用空格等文件名
汤姆·黑尔

大概是一种解释,因为您没有别名参数,而使用了函数。给定的功能只是与原始示例相反的一个示例。我不认为该人正在寻找通用垃圾功能。但是,为了提供更好的代码,我更新了答案。
埃文·朗格瓦伊斯

1
@FuzzyLogic-我花了几分钟试图在您的注释中解压缩代码。将很多代码打包到无法正确设置其格式的注释中,这是很多(有趣的)工作。我仍然没有弄清楚它到底是做什么的,更重要的是,为什么它支持您的(正确的)断言。

110

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

确实有可能通过via 将参数放入命令中间alias但这很丑陋。

小子,不要在家尝试这个!

如果您喜欢规避限制并做别人所说的不可能的事情,这就是秘诀。如果您的头发变淡并且脸部最终被油烟的疯狂科学家风格遮盖了,请不要怪我。

解决方法是将alias仅在末尾接受的参数传递给包装器,该包装器会将其插入到中间,然后执行命令。

解决方案1

如果您真的反对使用函数本身,则可以使用:

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

如果只需要第一个参数$@$1则可以替换为。

说明1

这将创建一个临时函数f,该函数将传递参数(注意f在最后调用)。当unset -f执行别名时,remove会删除函数定义,因此以后不会挂起。

解决方案2

您还可以使用一个子shell:

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

说明2

别名可生成类似以下的命令:

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

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

    单引号确保这些变量不会被交互式shell解释,并按字面意义传递给sh -c

    您可以使用双引号和\$@,但是最佳做法是用引号将其引号(因为它们可能包含空格),\"\$@\"看起来甚至更丑陋,但可以帮助您赢得一场混淆竞赛,其中蓬乱的头发是进入的先决条件。


2
对于解决方案1,请确保使用单引号,并避免在$ @附近使用\“。如果需要,可以使用一种非常有用的技术
。ty。– sgtz

解决方案1为我工作,为每个我想要的服务器在rdesktop-vrdp上加上参数。
谢谢尔

最后,接受参数正是我用简单的“ gc {branchname}”替换“ git checkout {branchname}”所需要的。在.bash_profile中,我只需添加alias gc='git checkout'
AbstractVoid19,2005年

@sgtz为什么要删除周围的引号$@?如果您有例如带有空格的文件,则它们是必需的。
汤姆·黑尔

@TomHale这有点语言学,但是如果有人真的反对使用函数(可能有任何原因),则解决方案1并没有真正的用处,因为您直接承认自己只是将函数的定义转移到了执行时间上。别名。其次,“ bash别名确实接受参数,但仅在末尾”是更多的语义:别名是按定义的单词替换字符串。它们不需要接受参数,但是通过替换执行的命令可以。别名是字符替换,仅此而已。没有?
BUFU

39

一种替代解决方案是使用marker,这是我最近创建的工具,可让您“标记”命令模板并将光标轻松放置在命令占位符上:

命令行标记

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


14

您要做的就是在别名中创建一个函数:

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

必须在“ $ 1”周围加上双引号,因为单引号将不起作用。


5
这很聪明,但是除了该问题确实指定要创建别名这一事实之外,是否有理由不仅仅使函数的名称最初与别名相同?
xaxxon

1
@xaxxon不是,但这是我知道使用别名而不是函数的最简单方法。
肯·特兰

1
这是行不通的。在Ubuntu 18上,我遇到错误bash: syntax error near unexpected token '{mkdir'
Shital Shah

缺少;函数内部的尾迹_mkcd很可能是错误的原因。
Jetchisel

{}
hesham_EE

10

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

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

参考文献:


??那是一个函数,而不是别名。您的参考资料之一就是这个问题。
2015年

2
不,它的工作原理完全像一个函数。就像这里解释的几个答案一样,您不能创建一个带参数的别名。您可以做的就是编写一个函数,这就是您已经做的。
2015年

1
@tripleee从我的bash新手角度来看,在阅读您的评论之前,我认为这是一个别名(创建别名的另一种方法)。据我所知,它的功能完全像一个。本质上,它是一个接受参数的别名,即使我不熟悉该术语。我没看到问题。我已经澄清了此问题中其他答案的链接。它帮助我创造了这个。
aliteralmind

1
也许这并没有具体回答“接受参数的bash别名”的问题,因为我现在知道这是不可能的,但肯定可以有效地回答它。我在这里想念什么?
2015年

2
这里有一些非常好的示例,以及注释良好的代码。对于来到此页面的人们有很大的帮助。

8

Bash别名绝对接受参数。我刚刚添加了一个别名来创建一个新的react应用程序,该应用程序接受应用程序名称作为参数。这是我的过程:

打开bash_profile以便在nano中进行编辑

nano /.bash_profile

添加别名,每行一个:

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

注意:“ $ @”接受传递的参数,例如“ creact my-new-app”

保存并退出Nano Editor

ctrl + o来写(按回车);Ctrl + x退出

告诉终端使用.bash_profile中的新别名

source /.bash_profile

而已!您现在可以使用新的别名


6

注意:如果这个主意不明显,则对别名以外的任何东西都使用别名是一个坏主意,第一个是“别名中的函数”,第二个是“难以读取的重定向/源代码”。此外,还有缺陷(我认为这很明显,但以防万一您感到困惑:我并不是说它们可以在任何地方被实际使用!)

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

我之前已经回答过,过去一直都是这样:

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

除非您避免同时使用函数,否则这是很好的做法。在这种情况下,您可以利用bash强大的重定向文本功能:

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

它们的长度大致相同,但要输入或输入几个字符。

真正起脚的时间差,顶部作为“函数法”和底部作为“重定向源”的方法。为了证明这一理论,时机不言而喻:

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个结果的底部,以随机间隔进行。函数创建/销毁似乎比重定向花费更多时间。希望这可以帮助将来的访客解决这个问题(不想让它自己解决)。


2
拥有一个定义函数的别名,然后运行该函数真是愚蠢。只需编写一个函数。对于几乎所有目的,别名都被shell函数取代。
盖尔哈2015年

万一您没有读完整个内容,可以尝试尝试,我在说明为什么使用function方法首先没有那么好,而且,它一点也不傻。仅仅因为您个人不喜欢它而停止发布和投票,或者至少给出有效的解释。呼唤名字是近距离接触的第一个迹象……
osirisgothra 2015年

1
第二个(bar别名)有几个副作用。首先,该命令不能使用stdin。其次,如果在别名之后未提供任何参数,则将通过外壳碰巧传递的所有参数。使用函数可以避免所有这些副作用。(也没用猫)。
盖尔哈2015年

2
嘿,我从未说过做任何事情都是好主意,我只是说过还有其他解决方法-这里的主要思想是您不应在别名中使用函数,因为它们比复杂函数还要慢重定向,我以为这很明显,但是我想我必须为每个人拼写出来(如果我这样做的话,我也会大喊大叫,因为帖子太肿了)
osirisgothra,2015年

1
由于bar的计时全为0,因此我怀疑Shell无法正确计时。请注意,在运行命令之前已打印了时间消息?因此,它什么都不计时然后执行小节,所以您根本就没有测量小节。做一些更复杂的事情,或者在酒吧中大循环,这样您就可以更清楚地知道自己什么都没
Evan Langlois 2015年

6

如果您正在寻找一种将所有参数应用于一个函数的通用方法,而不仅仅是一个或两个或一些其他硬编码量,则可以通过以下方式实现:

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

我喜欢这种$@基于解决方案的解决方案,因为它适用于任意数量的参数。


4
为什么不只是命名函数,runjar而不是使其成为函数的别名?似乎不必要地复杂!
埃文·朗格瓦

@EvanLanglois函数是在bash文件中自动alias-ed(或将事物的属性传递给alias)的吗?如果是的话,那只是我所不知道的
米卡

不明白你的意思。别名是另一个名称,可以是人或功能。因此,您创建了一个函数,然后为该函数命名了一个名字。别名没有什么特别的,别名只是第二个名称,不是必需的。您在命令行中键入的内容可以是内部或外部功能,因此“功能”是一个新命令,而不是别名。
埃文·朗格瓦伊斯

4
这是没有意义的。与相同alias runjar='java -jar myjar.jar'。别名确实接受参数,但只能在最后。
汤姆·黑尔

6

尊重所有说您不能在别名中间插入参数的人,我刚刚对其进行了测试,发现它确实有效。

别名mycommand =“ python3” $ 1“ script.py --folderoutput RESULTS /”

然后,当我运行mycommand foobar时,它的工作原理就像我直接键入命令一样。


绝对,别名可以获取参数,我已经使用了这一年龄,例如:alias commit =“ git commit -m $ 1”
agapitocandemor

对我不起作用:alias myalias="echo 1 "$1" 3"; myalias 2给我:1 3 2
dirdi

4

出于合理的技术原因,需要一种通用的解决方案来解决bash别名问题,而该机制不具有重新定位任意参数的机制。原因之一是,您希望执行的命令是否会由于执行功能而导致的环境变化受到不利影响。在所有其他情况下,应使用功能。

最近迫使我尝试解决此问题的原因是,我想创建一些缩写命令来打印变量和函数的定义。因此,我为此目的编写了一些函数。但是,某些变量会由函数调用本身更改(或可能会更改)。其中包括:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

我一直使用(在函数中)打印变量defns的基本命令。set命令输出的形式为:

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

例如:

> V=voodoo
sv V
V=voodoo

问题:这将不会在当前上下文中显示上述变量的定义,例如,如果在交互式shell提示符下(或不在任何函数调用中),则未定义FUNCNAME。但是我的函数告诉我错误的信息:

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

我想出的一种解决方案已在其他与此主题相关的文章中提及。对于此仅显示变量defns。且仅需要一个参数的命令,我这样做了:

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

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

> asv FUNCNAME
> echo $?
1

但是,我仍然感到必须寻找一种适用于任意数量参数的解决方案。

将任意参数传递给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".

例如:

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

关于此解决方案的一件好事是,在编写捕获的命令时,所有用于处理命令的位置参数(自变量)的特殊技巧都将起作用。唯一的区别是必须使用数组语法。

例如,

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

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

等等。


3

一旦我做了一些有趣的项目,我仍然使用它。当我通过cp命令coz 复制文件时,它显示了一些动画,cp但没有显示任何内容,这令人沮丧。所以我做了这个别名

alias cp="~/SCR/spiner cp"

这是微调脚本

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

看起来像这样

在此处输入图片说明

循环动画)

在此处输入图片说明


2

要获取参数,应使用函数!

但是,在创建别名时(而不是在别名执行期间)解释$ @并转义$也不起作用。我该如何解决这个问题?

您需要使用shell函数而不是别名来解决此问题。您可以如下定义foo:

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

要么

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

最后,使用以下语法调用foo():

foo arg1 arg2 argN

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

在您的情况下,这将起作用

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

我不明白你的想法。我认为对参数进行解释并不重要。别名最后接受尽可能多的参数。
Timo

但是最好用函数来做到这一点。别名并非用于此目的。
艾哈迈德·阿威斯

1

实际上,函数确实总是答案,正如手册页中的引用所充分说明的那样:“对于几乎所有目的,别名都被shell函数所取代。”

为了完整性,并且因为这可能是有用的(稍微轻量级的语法),应该注意的是,当参数遵循别名时,仍可以使用它们(尽管这不能满足OP的要求)。这可能是最容易通过示例演示的:

alias ssh_disc='ssh -O stop'

允许我输入像这样的smth ssh_disc myhost,它按预期扩展为:ssh -O stop myhost

这对于接受复杂参数的命令很有用(我的内存已不再是它的用途了……)


1

函数和别名都可以使用参数,如此处所示。此外,我还要指出其他两个方面:

1.函数在自己的作用域中运行,别名共享作用域

在需要隐藏或暴露某些东西的情况下,了解这种差异可能会很有用。它还表明,函数是封装的更好选择。

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 

输出:

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.包装脚本是一个更好的选择

我经历了好几次,当通过ssh或涉及切换用户名或多用户环境登录时,找不到别名或函数。有一些获取点文件的技巧和窍门,或者是一个有趣的别名别名:alias sd='sudo '让此后续别名alias install='sd apt-get install'按预期工作(请注意中的额外空间sd='sudo ')。但是,在这种情况下,包装脚本比函数或别名更好。包装脚本的主要优点是,它可以在预期的路径(即/ usr / loca / bin /)下可见/可执行,在该路径下必须先获得函数/别名才能使用。例如,您将一个函数放在〜/ .bash_profile或〜/ .bashrc中bash,用于,但是稍后切换到另一个shell(即zsh),则该功能不再可见。因此,当您有疑问时,包装脚本始终是最可靠和可移植的解决方案。


1
您为什么认为功能版本不起作用?
Tripleee

@tripleee。我已经修改了帖子,以使其更具可读性。在标题“ 1.别名起作用,函数...”下,我说明了为什么函数版本不起作用。也许直接回答这个问题,函数引入了别名没有的新范围。
biocyberman

您说这行不通,但我不相信您。source在一个函数中工作正常。
三人房

1
f () { source /tmp/nst; }完全符合我的期望。也许您PATH错了,所以它运行不正确activate或其他原因;但是source从函数运行可以正常工作。
三人房

1
BTW,重:使用function你定义关键字,请参阅wiki.bash-hackers.org/scripting/obsolete - function funcname {被用于预POSIX弹向后兼容古老的ksh语法bash的支持,而funcname() {为官方POSIX,标准化的语法。function funcname() {是对与古代ksh不兼容与POSIX sh 不兼容的两者的误解,因此最好避免。
Charles Duffy

1

这是示例:

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

很重要:

  1. {前后都有一个空间}
  2. 有一个;在序列中的每个命令之后。如果您在最后一条命令后忘记了此内容,则会看到>提示!
  3. 该参数用引号引起来,例如 "$1"

2
无需为函数创建别名,只需直接使用该函数即可。
user3439894

1

正如其他人已经指出的那样,使用函数应被视为最佳实践。

但是,这是另一种利用方法xargs

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

注意,这对流的重定向有副作用。


0

您无需执行任何操作,alias会自动执行此操作。

例如,如果我想使git pull origin master参数化,我可以简单地创建一个别名,如下所示:

alias gpull = 'git pull origin '

实际调用它时,您可以将“ master”(分支名称)作为参数传递,如下所示:

gpull master
//or any other branch
gpull mybranch

这不能回答问题,因为参数不能随意放置,而只能放在最后。
迪迪
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.