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

时间:2013-11-01 02:58:58

标签: linux bash shell

我正在我的VM中运行多个Web应用程序,这些应用程序位于Ubuntu 12.04上。

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

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

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

这是一个懒惰的程序员,询问我是否有办法输入。

  • go_app1
  • go_app2
  • go_app3

我知道如何使用bash脚本执行上述操作。

但我最终会输入

./GoApp.sh -app app1

我想通过输入go_app1来使它更优雅。

么?

修改

我使用了排名靠前的答案,我在Ubuntu中收到了此错误消息。

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

我哪里出错了?

EDIT2:

我已在command not found message when I try to add command in .bashrc处将错误重写为另一个问题。

6 个答案:

答案 0 :(得分:3)

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

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

用法:

go_app 1

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

答案 1 :(得分:2)

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

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

执行此操作后,键入go_app1应更改目录。

答案 2 :(得分:2)

通过bash命令历史搜索是否是一个足够好的解决方案?我还经常需要登录长目录结构,但我通常都是Ctrl-R。例如,如果我最近刚进入你的app1.com,我会按 按Ctrl-R 然后键入app1.com并显示使用app1.com的最后一个命令,此时按Enter键即可完成。如果“cd”不是那个,则再按Ctrl-R几次直到它出现。

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

当然,这只有在你关心你输入的数量时才有效,而不是你想以编程方式进行此操作,并且只有当“cd”命令在具有“ app1.com“(或任何其他简短的区分模式)明确。

答案 3 :(得分:0)

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

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

然后我可以说:

 cd app1.com

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

答案 4 :(得分:0)

改进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而没有进一步的参数)。

答案 5 :(得分:0)

.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存在,并且此函数在被调用时只会cd进入该目录。 / p>

看(别担心,我在沙盒中):

# 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放在两个不同的地方并不是一个好主意,所以你要使用全局变量,你最终会在{{1}中得到这个结果。 }:

.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 _go_apps_basedir,因此不会无意中更改。这次我选择在阅读中使用readonlyIFS=''以及-d ''命令中的-printf '%f\0',以向您展示在解析输出时如何安全地执行操作find


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

_make_go_apps

对不起对于这个长篇大论的帖子......我或多或少地在打字时思考(不好做!),我从不想删除以前的部分,因为它们包含有趣的内容东西。


修改即可。现在,为了使这篇文章更长,这里是相同的,但这将为readonly _go_apps_basedir=/var/virtual make_go_apps() { local f d 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