我曾经使用 CShell (csh),它可以让您创建一个带参数的别名。符号类似于
alias junk="mv \\!* ~/.Trash"
在 Bash 中,这似乎不起作用。鉴于 Bash 有许多有用的功能,我会假设这个功能已经实现,但我想知道如何实现。
"$1"
周围使用引号
alias test_args="echo PREFIX --$1-- SUFFIX"
,当使用 test_args ABCD
调用时会产生以下控制台输出 PREFIX ---- SUFFIX ABCD
do
结尾的别名将不可能或不切实际地编写为函数。其次,对于 all 别名,您可以方便地使用 ZSH 中的 A-a
或 Bash 中的 C-A-e
(或您配置的任何内容)扩展别名,而函数没有这样的功能。
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; }
mv "$1" "$1.bak"; cp "$2" "$1"
更改为 mv "$1" "$1.bak" && cp "$2" "$1"
以在 mv
遇到问题(例如,文件系统已满)时不会丢失您的数据。
这个问题只是问错了。您不需要创建一个带参数的别名,因为 alias
只是为已经存在的东西添加了第二个名称。 OP 想要的功能是创建新函数的 function
命令。您不需要为该函数命名,因为该函数已经有一个名称。
我想你想要这样的东西:
function trash() { mv "$@" ~/.Trash; }
而已!您可以使用参数 $1、$2、$3 等,或者只使用 $@ 填充它们
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
$@
以支持带有空格等的文件名。
TL;DR:改为这样做
使用函数比将参数放在命令中间的别名更容易且更易读。
$ wrap_args() { echo "before $@ after"; }
$ wrap_args 1 2 3
before 1 2 3 after
如果你继续阅读,你会学到一些你不需要知道的关于 shell 参数处理的东西。知识是危险的。在黑暗面永远控制你的命运之前,得到你想要的结果。
澄清
bash
别名 do 接受参数,但仅在 结束:
$ alias speak=echo
$ speak hello world
hello world
通过 alias
将参数放入命令的 middle 确实是可能的,但它会变得丑陋。
不要在家里尝试这个,孩子们!
如果你喜欢规避限制并做别人说不可能的事,这里就是秘诀。如果你的头发变得蓬乱并且你的脸最终被煤烟疯狂科学家式覆盖,请不要责怪我。
解决方法是将 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'\'' _'
解释2
别名构建如下命令:
sh -c 'echo before "$@" after' _
注释:
占位符 _ 是必需的,但它可以是任何东西。它被设置为 sh 的 $0,并且是必需的,这样用户给定的参数中的第一个就不会被消耗。演示:sh -c 'echo 已使用:“$0” 打印:“$@”' 酒精醉酒 已使用:酒精 打印:醉酒 babble
单引号内的单引号是必需的。下面是一个不使用双引号的示例: $ sh -c "echo Consumed: $0 Printing: $@" Alcoholdrinken babble Consumed: -bash Printing: 这里交互式 shell 的 $0 和 $@ 的值被替换为双引号在传递给 sh 之前引用。证明如下: echo "Consumed: $0 Printing: $@" Consumed: -bash Printing: 单引号确保这些变量不会被交互式 shell 解释,而是按字面意思传递给 sh -c。您可以使用双引号和 \$@,但最佳做法是引用您的论点(因为它们可能包含空格),并且 \"\$@\" 看起来更丑陋,但可能会帮助您赢得一场头发蓬乱的混淆竞赛是进入的先决条件。
alias gc='git checkout'
$@
周围的引号?例如,如果您有包含空格的文件,则它们是必需的。
\df
您所要做的就是在别名中创建一个函数:
$ alias mkcd='_mkcd(){ mkdir "$1"; cd "$1";}; _mkcd'
^ * ^ ^ ^ ^ ^
您必须在 "$1" 周围加上双引号,因为单引号不起作用。这是因为在标有箭头的地方与引号发生冲突会使系统感到困惑。此外,该功能需要在标有星号的位置留出空间。
bash: syntax error near unexpected token '{mkdir'
。
function
前缀,请参阅 wiki.bash-hackers.org/scripting/obsolete 中的讨论。也就是说,我不知道为什么有人会这样做而不是只定义一个函数而不使用任何别名。
command
。您甚至可以使用 alias c = 'command'
之类的别名,然后只需使用 c ls
。
另一种解决方案是使用 marker,这是我最近创建的一个工具,它允许您“标记”命令模板并轻松地将光标放在命令占位符上:
https://i.stack.imgur.com/0fyiS.gif
我发现大多数时候,我都在使用 shell 函数,所以我不必在命令行中一次又一次地编写常用命令。在这个用例中使用函数的问题是在我的命令词汇表中添加新术语,并且必须记住实际命令中的函数参数指的是什么。标记的目标是消除这种精神负担。
一旦我做了一些有趣的project,我仍然使用它。当我通过 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
它看起来像这样
https://i.stack.imgur.com/e3DAc.gif
循环动画)
https://i.stack.imgur.com/kTUMZ.gif
这是上述 color 脚本的链接。和新的动画周期)
https://i.stack.imgur.com/ifc5n.gif
句法:
alias shortName="your custom command here"
例子:
alias tlogs='_t_logs() { tail -f ../path/$1/to/project/logs.txt ;}; _t_logs'
>
提示,请确保您在 }
之前获得了 ;
。另请注意,每次使用别名时都会重新定义函数,因此如果函数定义很昂贵,最好将其移出 alias
。
alias kj='_kc_jq() { kc get -o json $@ |jq; }; _kc_jq'
Bash 别名绝对接受参数。我刚刚添加了一个别名来创建一个新的反应应用程序,它接受应用程序名称作为参数。这是我的过程:
在 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”
保存并退出 nano 编辑器
ctrl+o 写入(按回车键); ctrl+x 退出
告诉终端使用 .bash_profile 中的新别名
source /.bash_profile
而已!您现在可以使用新别名
gitc foo
运行 git commit -m foo
不是因为您有 $@ 而是因为 foo 出现在最后——它正在运行 git commit -m
并且您碰巧有一个 foo
紧随其后并被附加,这使您的命令有效。
$@
。
set -- "first argument" "second argument"
,则所有 "$@"
都将变成 "first argument" "second argument"
。它们不反映传递给别名的参数;它们只反映在调用别名的上下文中处于活动状态的参数。
以下是我在 ~/.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
}
参考:
从字符串中修剪空格:如何从 Bash 变量中修剪空格?
实际换行符:https://stackoverflow.com/a/4296147/2736496
带参数的别名: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
尊重所有那些说你不能在别名中间插入参数的人,我刚刚测试了它,发现它确实有效。
alias mycommand = "python3 "$1" script.py --folderoutput RESULTS/"
然后,当我运行 mycommand foobar 时,它的工作方式就像我以手写方式输入命令一样。
alias myalias="echo 1 "$1" 3"; myalias 2
给我:1 3 2
alias mycommand = "python3 script.py --folderoutput RESULTS/"
(省略 "$1"
)。相同,因为 alias 在 bash 中没有设置位置参数。在交互式 shell 中,它们的值是 "" 一个空字符串,除非你在里面放了一些东西。为了进一步测试,在定义别名之前尝试真正添加一些东西到 $1: set -- something
。现在您的别名很可能已损坏,请查看该别名包含的内容:alias mycommand
$1
被空字符串替换并且您的评论被附加。您可以安全地将您的别名重新定义为 git commit -m
,它仍然可以工作。
如果您正在寻找一种将所有参数应用于函数的通用方法,而不仅仅是一个或两个或其他一些硬编码量,您可以这样做:
#!/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
。
我喜欢这个基于 $@
的解决方案,因为它适用于任意数量的参数。
runjar
而不是将其设为函数的别名?看起来不必要的复杂!
alias
编辑(或将事物的属性传递给 alias
)?如果是,那只是我不知道
alias runjar='java -jar myjar.jar'
相同。别名确实接受参数,但仅在最后。
注意:如果这个想法不明显,那么将别名用于除别名之外的任何东西都是一个坏主意,第一个是“别名中的函数”,第二个是“难以阅读的重定向/源”。此外,也存在缺陷(我认为这很明显,但以防万一你感到困惑:我并不是说它们实际上可以用于......任何地方!)
..................................................... ..................................................... ..................................................
这个我以前回答过,过去一直是这样的:
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 个结果的底部,以随机间隔完成。似乎函数创建/销毁比重定向花费更多时间。希望这将有助于未来的访问者解决这个问题(不想让自己知道)。
time for i in {1..1000}; do foo FOOVALUE; done
→ 0m0.028s。但是 time for i in {1..1000}; do bar FOOVALUE; done
→ 0m2.739s。 Bar 比 foo 慢两个数量级。仅使用普通函数而不是别名将运行时间再缩短 30%:function boo() { echo "arg1 for boo=$1" ; }
⇒ time for i in {1..1000}; do boo FOOVALUE; done
→ 0m0.019s。
我将发布我的(希望是好的)解决方案(供未来的读者,最重要的是;编辑)。所以 - 请编辑和改进/删除这篇文章中的任何内容。
在终端:
$ 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
$f
在末尾。 $f
在别名定义时可能为空,因此解析为 alias CAT_FILE_="cat "
。只需运行 alias
即可查看生成的定义。因此,当您调用 CAT_FILE_
时,您只需将参数传递给别名,就像 alias ll="ls -l"
中的任何其他别名用法一样。尝试将“参数” $f
放在其他地方而不是最后,这将不起作用。例如:alias ECHO_ARG_$f="echo xxx $f yyy"
。然后 ECHO_ARG_ test
通向 xxx yyy test
。
有正当的技术原因需要一个通用的解决方案来解决 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 junk=xargs -I \"{}\" -- mv \"{}\" \"~/.Trash\" <<<"
)。
xargs
没有进行文本替换(它对在 shell 解析已经结束后生成的 C 字符串数组进行操作,所以引号不再具有改变 shell 行为的价值) ,并且当引用 ~
时不起作用。所以这会更好,只是 alias junk='xargs -I {} -- mv {} ~/.Trash <<<'
这是示例:
alias gcommit='function _f() { git add -A; git commit -m "$1"; } ; _f'
很重要:
{ 之后和 } 之前有一个空格。有一个;在每个命令之后。如果您在最后一个命令之后忘记了这一点,您将看到 > 提示!参数用引号括起来,如 "$1"
要具体回答有关创建别名以将文件移动到垃圾箱文件夹而不是删除它们的问题:
alias rm="mv "$1" -t ~/.Trash/"
当然,您必须先创建 dir ~/.Trash。
然后只需给出以下命令:
$rm <filename>
$rm <dirname>
alias rm="mv "$i_bellieve_this_is_correct_because_it_WORKS" -t ~/.Trash/"
仍然不相信的人可以在之前运行此命令:set -- my_very_important_file
如果您确信 $1 在别名中有效,请按字面意思运行它或使用指向您非常重要文件的路径。 now 声明:建议的 alias rm="mv "$1" -t ~/.Trash/"
和 rm <filename>
。 set --
将值设置为位置参数 $1。别名命令没有。
$1
完全为空,mv
仍然尊重尾随位置的参数。 $1
不是由传递给别名的参数填充;它是从运行别名的 shell 中预先存在的 $1
值填充的。
使用子命令的解决方案:
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 ...
函数确实几乎总是答案,因为手册页中的这句话已经充分贡献并证实了这一点:“对于几乎所有目的,别名都被 shell 函数所取代。”
为了完整起见并且因为这可能有用(略微更轻量级的语法),可以注意到当参数跟随别名时,它们仍然可以使用(尽管这不能满足 OP 的要求)。这可能是最容易用一个例子来证明的:
alias ssh_disc='ssh -O stop'
允许我像 ssh_disc myhost
一样键入 smth,它会按预期扩展为:ssh -O stop myhost
这对于需要复杂参数的命令很有用(我的记忆不再是它使用的东西了......)
要获取参数,您应该使用函数!
但是 $@ 在创建别名而不是在执行别名期间被解释并且转义 $ 也不起作用。我该如何解决这个问题?
您需要使用 shell 函数而不是别名来摆脱这个问题。您可以定义 foo 如下:
function foo() { /path/to/command "$@" ;}
或者
foo() { /path/to/command "$@" ;}
最后,使用以下语法调用 foo():
foo arg1 arg2 argN
确保将 foo() 添加到 ~/.bash_profile
或 ~/.zshrc
文件。
在您的情况下,这将起作用
function trash() { mv $@ ~/.Trash; }
函数和别名都可以使用其他人在此处显示的参数。此外,我想指出其他几个方面:
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.包装脚本是更好的选择
我遇到过好几次在 logging in via ssh
或涉及切换用户名或多用户环境时找不到别名或函数的情况。获取点文件有一些技巧和窍门,或者这个有趣的别名:alias sd='sudo '
让这个后续的别名 alias install='sd apt-get install'
按预期工作(注意 sd='sudo '
中的额外空间)。但是,在这种情况下,包装脚本比函数或别名更有效。包装脚本的主要优点是它在预期路径(即/usr/loca/bin/)下是可见/可执行的,其中作为函数/别名需要在它可用之前获取源。例如,您在 ~/.bash_profile 或 ~/.bashrc 中为 bash
放置了一个函数,但稍后切换到另一个 shell(即 zsh
),则该函数不再可见。因此,当您有疑问时,包装脚本始终是最可靠和可移植的解决方案。
source
在函数中工作得很好。
f () { source /tmp/nst; }
完全符合我的预期。也许您的 PATH
是错误的,所以它运行错误的 activate
或其他东西;但从函数运行 source
工作正常。
function
关键字,请参阅 wiki.bash-hackers.org/scripting/obsolete - function funcname {
是古老的 ksh 语法 bash 支持向后兼容 pre-POSIX shell,而 funcname() {
是官方 POSIX 标准化语法。 function funcname() {
是与古代 ksh 或与 POSIX sh 不兼容的两者的混搭,因此最好避免。
这是使用 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[@]}"
mv
有一个 -t
选项,它以不同的方式解决该特定命令的问题。)
不定期副业成功案例分享
$1
括起来吗?source
.bashrc 将添加该函数,但不会取消旧别名的别名。由于别名的优先级高于函数,因此它将尝试使用别名。您需要关闭并重新打开 shell,或者调用unalias <name>
。也许我会节省我刚刚浪费的 5 分钟。exec bash
:它将启动一个新的 shell,让您清楚地阅读您的配置,就像您关闭并重新打开一样,但保留该会话的环境变量设置也一样。此外,当您想要处理像堆栈一样的思考时,不带 exec 执行bash
会很有用。mv "$1" "$1.bak"
。如果没有引号,如果 $1 是“hello world”,您将执行mv hello world hello world.bak
而不是mv "hello world" "hello world.bak"
。