如何在bash shell中编写一个漂亮优雅的linux命令

我正在Ubuntu 12.04上的虚拟机中运行多个Web应用程序。

当我进入我的虚拟机时,我发现自己经常input以下内容。

  • cd /var/virtual/app1.com/
  • cd /var/virtual/app2.com/
  • cd /var/virtual/app3.com/

每行代表一个单独的webapp根目录,供我执行某些指令。

这是懒惰的程序员询问是否有方法让我input。

  • go_app1
  • go_app2
  • go_app3

我知道如何使用bash脚本来完成上述操作。

但我最终会打字

 ./GoApp.sh -app app1 

我想通过简单地inputgo_app1来使它更加优雅。

build议吗?

编辑:

我使用了评分最高的答案,并在Ubuntu中收到了此错误消息。

https://gist.github.com/simkimsia/7336019

我哪里做错了?

EDIT2:

当我尝试在.bashrc中添加命令时,我将这个错误改写成了另外一个问题。

为每个定义一个别名肯定会起作用。 但是,由于模式之后有多个所需的快捷方式,请考虑一个函数。

 function go_app() { cd /var/virtual/app$1.com/; } 

用法:

 go_app 1 

把函数定义放在〜/ .bashrc中。

您可以通过将下面的内容放在.bash_profile中来使用别名。

 alias go_app1='cd /var/virtual/app1.com/' 

这样做后,输入go_app1应该改变你的目录。

通过bash命令历史搜索是一个足够好的解决方案吗? 我也经常登录到长目录结构,但我通常通过Ctrl-R。 比如,如果我刚刚在你的app1.com上输入了cd-ed,我会按下Ctrl-R,然后输入app1.com,最后一个使用app1.com的命令就会出现,此时按回车键就完成了。 如果“cd”不是那个,那么你再按几次Ctrl-R直到它出现。

更详细一点: http : //www.catonmat.net/blog/the-definitive-guide-to-bash-command-line-history/

当然,只有当你关心你输入了多少,而不是如果你试图以编程的方式执行这个操作,并且只有当“cd”命令在具有“app1.com”的命令列表中相当近时“(或任何其他短的区别模式)明确。

我将$CDPATH变量(在bash )设置为所有要搜索的目录,包括当前目录(首先),如:

  export CDPATH=.:/var/virtual:<other-dirs> 

那么我只能说:

  cd app1.com 

鉴于目录名称很短,我可以键入(而不是通过历史搜索)

改进了corkin别名的建议,但给予了“命名”(具有参数app1.com,app2.com,…)的灵活性,该解决方案通过一个别名来解决:

 alias go_app='cd /var/virtual/; cd ' 

之后,

 go_app app1.com 

cd放入/var/virtual/app1.com/。 在命名上:我将它命名为cd_app 。 在旁边注意go_app没有参数将踢你回到你的家(因为最后一个命令是cd没有进一步的参数)。

在你的.bashrc加入这个:

 _make_go_apps() { local r=/var/virtual local d qd while read d; do printf -v qd '%q' "$r/$d" eval "go_${d%.com}() { cd -- $qd; }" done < <( find "$r" -maxdepth 1 -regex ".*/app[0-9]+\.com" -type d -printf '%f\n') } 

这将创建一个函数go_appX其中X是一个数字,这样目录/var/virtual/appX.com存在了,这个函数在被调用的时候只会进入该目录。

看(别担心,我在沙箱里):

 # mkdir -p /var/virtual/app{1..50}.com # _make_go_apps # go_app42 # pwd /var/virtual/app42 

完成!

如果创建了新目录,则只需重新启动_make_go_apps函数。

这种方法满足了所有OP的要求,并且通用性足以应付任何数目的目录。

eval是邪恶的,但以一种安全的方式使用(即使在这里没有用处,也可以用清理过的变量来读取;但是如果有一天你想概括一下这个方法,至少这个部分是正确的)。

除非你完全知道你在做什么,否则不要试图概括这个方法:注意包含空格,换行符,尾随换行符等的文件名。

备注。

  • 如果要更改位置/var/virtual ,只需更改局部变量r ,确保它是绝对路径。
  • 选项卡完成课程工作得很好(和选项卡将显示您的可能性)。
  • 如果删除了一些目录,则可能需要_clean_go_apps只保留相关的go_appX 。 一种可能性是(它会进入你的.bashrc ):

     clean_go_apps() { local r=/var/virtual local f while read _ _ f; do [[ $f =~ ^go_app[[:digit:]]+$ ]] || continue [[ -d $r/${f#go_}.com ]] && continue unset -f $f done < <(declare -F) } 

    在这种情况下,阅读下一部分。


然后你会意识到在两个不同的地方有/var/virtual不是一个好主意,所以你需要使用一个全局变量,最后在你的.bashrc包含这个变量:

 readonly _go_apps_basedir=/var/virtual make_go_apps() { local d qd while IFS= read -d '' d; do printf -v qd '%q' "$_go_apps_basedir/$d" eval "go_${d%.com}() { cd -- $qd; }" done < <( find "$_go_apps_basedir" -maxdepth 1 -regex ".*/app[0-9]+\.com" -type d -printf '%f\0') } clean_go_apps() { local f while read _ _ f; do [[ $f =~ ^go_app[[:digit:]]+$ ]] || continue [[ -d "$_go_apps_basedir/${f#go_}.com" ]] && continue unset -f $f done < <(declare -F) } make_go_apps 

readonly了变量_go_apps_basedir ,以便它不会被无意中更改。 这一次,我选择在读命令中使用IFS=''-d '' ,并在find命令中使用-printf '%f\0'来展示如何在解析find的输出时执行安全的操作。


我仍然关心_make_go_apps函数中的_make_go_apps ,因为它不是100%纯bash解决方案。 这是一个100%纯bash解决方案:

 readonly _go_apps_basedir=/var/virtual make_go_apps() { local fd qd saved_shopt saved_shopt=$(shopt -p) shopt -s extglob nullglob for d in "$_go_apps_basedir"/app+([[:digit:]]).com/; do f=${d#$_go_apps_basedir/} printf -v qd '%q' "$d" eval "go_${f%.com/}() { cd -- $qd; }" done eval "$saved_shopt" } clean_go_apps() { local f while read _ _ f; do [[ $f =~ ^go_app[[:digit:]]+$ ]] || continue [[ -d "$_go_apps_basedir/${f#go_}.com" ]] && continue unset -f $f done < <(declare -F) } make_go_apps 

对不起 ,这是一个长的杂乱的帖子…我在打字的时候或多或少都在想(不好做!),我从来不想抹去以前的部分,因为它们包含有趣的东西。


编辑 。 现在,为了使这篇文章更长时间,这里是一样的,但是这将创建一个go_X函数为每个目录X.com里面/var/virtual ,使X只包含字符: [0-9a-zA-Z\-\._] 。 把这个放在你的.bashrc

 readonly _go_apps_basedir=/var/virtual make_go_functions() { local fd qd saved_shopt saved_shopt=$(shopt -p) shopt -s extglob nullglob for d in "$_go_apps_basedir"/+([[:alpha:][:digit:]\-\._]).com/; do f=${d#$_go_apps_basedir/} printf -v qd '%q' "$d" eval "go_${f%.com/}() { cd -- $qd; }" done eval "$saved_shopt" } clean_go_apps() { local f while read _ _ f; do [[ $f =~ ^go_.+$ ]] || continue [[ -d "$_go_apps_basedir/${f#go_}.com" ]] && continue unset -f $f done < <(declare -F) } make_go_functions