繁体   English   中英

制作一个带参数的 Bash 别名?

[英]Make a Bash alias that takes a parameter?

我曾经使用 CShell ( ),它可以让你创建一个带有参数的别名。 符号是这样的

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

在Bash,这个好像不行。 鉴于 Bash 具有许多有用的功能,我认为这个功能已经实现,但我想知道如何实现。

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 函数可以作为 shell 中的命令使用。 因此,例如您可以像这样调用较早的函数

$ myfunction original.conf my.conf

完善上面的答案,您可以获得像别名一样的 1 行语法,这对于 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; }

这个问题只是问错了。 您不会创建带有参数的别名,因为alias只是为已经存在的东西添加了第二个名称。 OP 想要的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仅在最后接受的参数传递给包装器,该包装器将它们插入中间,然后执行您的命令。

解决方案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在执行别名时删除函数定义,因此它之后不会挂起。

解决方案2

您还可以使用子shell:

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

说明二

别名构建一个命令,如:

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

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

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

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

必须在 "$1" 周围加上双引号,因为单引号不起作用。 这是因为在标有箭头的地方冲突引号会混淆系统。 此外,该功能需要在标有星号的地方留出空间。

另一种解决方案是使用marker ,这是我最近创建的一个工具,它允许您“标记”命令模板并轻松地将光标放在命令占位符上:

命令行标记

我发现大部分时间,我都在使用 shell 函数,因此我不必在命令行中一遍又一遍地编写常用命令。 在这个用例中使用函数的问题是在我的命令词汇表中添加新术语,并且必须记住实际命令中参数所指的函数。 Marker 的目标是消除这种心理负担。

一旦我做了一些有趣的项目,我仍然在使用它。 当我通过cp命令复制文件时,它显示了一些动画,因为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

它看起来像这样

在此处输入图片说明

循环动画)

在此处输入图片说明

这是上面提到的颜色脚本的链接。 和新的动画循环)

在此处输入图片说明

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

在 nano 中打开 bash_profile 进行编辑

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”

保存并退出纳米编辑器

ctrl+o 写入(按回车键); ctrl+x 退出

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

source /.bash_profile

就是这样! 您现在可以使用新别名

尊重所有那些说你不能在别名中间插入参数的人,我刚刚测试了它并发现它确实有效。

alias mycommand = "python3 "$1" script.py --folderoutput RESULTS/"

然后,当我运行 mycommand foobar 时,它的工作方式与我手写命令时完全一样。

这是我在~/.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
}

参考:

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

#!/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运行了runjar hi there它最终会实际运行java -jar myjar.jar hi there 如果我确实runjar one two three它会运行java -jar myjar.jar one two three

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

句法:

alias shortName="your custom command here"

例子:

alias tlogs='_t_logs() { tail -f ../path/$1/to/project/logs.txt ;}; _t_logs'

注意:如果这个想法不明显,除了别名之外的任何东西都使用别名是一个坏主意,第一个是“别名中的函数”,第二个是“难以阅读的重定向/源”。 此外,也有缺陷(我认为这很明显,但以防万一你感到困惑:我并不是说它们实际上可以用于......任何地方!)

………………………………………………………………………………………………………………………………………………………… ………………………………………………………………………………………………………………………………………………………… ……………………………………………………………………………………………………………………………………………………………………………………

这个我以前回答过,过去一直是这样:

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 个结果的底部,以随机间隔完成。 似乎函数创建/销毁比重定向花费更多的时间。 希望这将有助于这个问题的未来访问者(不想把它留给我自己)。

有合法的技术原因需要一个通用的解决方案来解决 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[@]}”。

等等。

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

但是,这是另一种利用xargs

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

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

我将发布我的(希望如此)解决方案(对于未来的读者,最重要的是;编辑)。
所以 - 请编辑和改进/删除这篇文章中的任何内容。

在终端:

$ alias <name_of_your_alias>_$argname="<command> $argname"

并使用它(注意'_'后面的空格:

$<name_of_your_alias>_ $argname

例如, cat名为hello.txt的文件的别名:

  • (别名是CAT_FILE_
  • $f (是$argname ,在这个例子中是一个文件)
$ alias CAT_FILE_$f="cat $f"

$ echo " " >> hello.txt
$ echo "hello there!" >> hello.txt
$ echo " " >> hello.txt
$ cat hello.txt

    hello there!

测试(注意'_'后面的空格):

CAT_FILE_ hello.txt

要对有关创建别名以将文件移动到垃圾箱文件夹而不是删除它们的问题给出具体答案:

alias rm="mv "$1" -t ~/.Trash/"

当然,您必须先创建 dir ~/.Trash 。

然后只需给出以下命令:

$rm <filename>
$rm <dirname>

对于取参数,您应该使用函数!

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

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

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

或者

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

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

foo arg1 arg2 argN

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

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

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

这是示例:

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

很重要:

  1. {之后和}之前有一个空格。
  2. 有一个; 依次在每个命令之后。 如果您在最后一个命令之后忘记了这一点,您将看到>提示符!
  3. 参数用引号括起来作为"$1"

函数确实几乎总是答案,正如手册页中的这句话已经充分贡献和证实的那样: “对于几乎所有目的,别名都被 shell 函数取代。”

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

alias ssh_disc='ssh -O stop'

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

这对于采用复杂参数的命令很有用(我的记忆不再是它使用的......)

函数和别名都可以像其他人在此处显示的那样使用参数。 此外,我想指出其他几个方面:

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 '的额外空间sd='sudo ' )。 但是,在这种情况下,包装脚本比函数或别名更有效。 包装器脚本的主要优点是它在预期路径(即 /usr/loca/bin/)下是可见/可执行的,其中作为函数/别名需要在它可用之前找到它。 例如,您将一个函数放在 ~/.bash_profile 或 ~/.bashrc 中用于bash ,但稍后切换到另一个外壳程序(即zsh )然后该函数不再可见。 因此,当您有疑问时,包装脚本始终是最可靠和可移植的解决方案。

使用子命令的解决方案:

d () {
    if [ $# -eq 0 ] ; then
        docker
        return 0
    fi
    CMD=$1
    shift

    case $CMD in
    p)
        docker ps --all $@
        ;;
    r)
        docker run --interactive --tty $@
        ;;
    rma)
        docker container prune
        docker image prune --filter "dangling=true"
        ;;
    *)
        docker $CMD $@
        ;;
    esac
    return $?
}

使用:

$ d r my_image ...

调用:

docker run --interactive --tty my_image ...

我个人使用Bash,在我的VPS上使用〜/ .aliases这个,它可以完美地工作:

别名ban =“ sudo ufw拒绝$ @”

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

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

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

这是使用read另一种方法。 我正在使用它通过名称片段粗暴搜索文件,忽略“权限被拒绝”消息。

alias loc0='{ IFS= read -r x; find . -iname "*" -print 2>/dev/null | grep $x;} <<<'

一个简单的例子:

$ { IFS= read -r x; echo "1 $x 2 ";} <<< "a b"
1 a b 2 

请注意,这会将参数作为字符串转换为变量。 为此,可以在引号内使用多个参数,空格分隔:

$ { read -r x0 x1; echo "1 ${x0} 2 ${x1} 3 ";} <<< "a b"
1 a 2 b 3 
alias junk="delay-arguments mv _ ~/.Trash"

delay-arguments脚本:

#!/bin/bash

# Example:
# > delay-arguments echo 1 _ 3 4 2
# 1 2 3 4
# > delay-arguments echo "| o n e" _ "| t h r e e" "| f o u r" "| t w o"
# | o n e | t w o | t h r e e | f o u r

RAW_ARGS=("$@")

ARGS=()

ARG_DELAY_MARKER="_"
SKIPPED_ARGS=0
SKIPPED_ARG_NUM=0
RAW_ARGS_COUNT="$#"

for ARG in "$@"; do
  #echo $ARG
  if [[ "$ARG" == "$ARG_DELAY_MARKER" ]]; then
    SKIPPED_ARGS=$((SKIPPED_ARGS+1))
  fi
done

for ((I=0; I<$RAW_ARGS_COUNT-$SKIPPED_ARGS; I++)); do
  ARG="${RAW_ARGS[$I]}"
  if [[ "$ARG" == "$ARG_DELAY_MARKER" ]]; then
    MOVE_SOURCE_ARG_NUM=$(($RAW_ARGS_COUNT-$SKIPPED_ARGS+$SKIPPED_ARG_NUM))
    MOVING_ARG="${RAW_ARGS[$MOVE_SOURCE_ARG_NUM]}"
    if [[ "$MOVING_ARG" == "$ARG_DELAY_MARKER" ]]; then
      echo "Error: Not enough arguments!"
      exit 1;
    fi
    #echo "Moving arg: $MOVING_ARG"
    ARGS+=("$MOVING_ARG")
    SKIPPED_ARG_NUM=$(($SKIPPED_ARG_NUM+1))
  else
    ARGS+=("$ARG")
  fi
done

#for ARG in "${ARGS[@]}"; do
  #echo "ARGN: $ARG"
#done

#echo "RAW_ARGS_COUNT: $RAW_ARGS_COUNT"
#echo "SKIPPED_ARGS: $SKIPPED_ARGS"

#echo "${ARGS[@]}"
QUOTED_ARGS=$(printf ' %q' "${ARGS[@]}")
eval "${QUOTED_ARGS[@]}"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM