简体   繁体   English

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

[英]how to write a beautifully elegant linux command in bash shell

I'm running several web applications in my VM which is on Ubuntu 12.04. 我正在我的VM中运行多个Web应用程序,这些应用程序位于Ubuntu 12.04上。

I find myself typing the following very often when I ssh into my VM. 当我进入我的虚拟机时,我发现自己经常输入以下内容。

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

Each line represents a separate webapp root directory for me to perform certain instructions. 每行代表一个单独的webapp根目录,供我执行某些指令。

This is the lazy programmer asking if there is a way for me to type. 这是懒惰的程序员,询问我是否有办法输入。

  • go_app1
  • go_app2
  • go_app3

I know how to do the above using bash script. 我知道如何使用bash脚本执行上述操作。

but I will end up typing 但我最终会打字

./GoApp.sh -app app1

I want to make it more elegant by simply typing go_app1. 我想通过输入go_app1来使它更优雅。

Advice? 建议吗?

EDIT: 编辑:

I used the top-rated answer and I got this error message in Ubuntu. 我使用了顶级答案,我在Ubuntu中收到此错误消息。

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

Where did I go wrong? 我哪里做错了?

EDIT2: EDIT2:

I have rewritten the error into another question here at command not found message when I try to add command in .bashrc . 当我尝试在.bashrc中添加命令时,我已经命令未找到消息时将错误重写为另一个问题。

Defining an alias for each will certainly work. 为每个定义别名肯定会有效。 But since you have multiple desired shortcuts following a pattern, consider a function. 但由于您在模式后面有多个所需的快捷方式,因此请考虑一个函数。

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

Usage: 用法:

go_app 1

Put the function definition in ~/.bashrc. 将函数定义放在〜/ .bashrc中。

You could use an alias by placing the below in your .bash_profile. 您可以通过将以下内容放在.bash_profile中来使用别名。

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

After doing that, typing go_app1 should change your directory. 完成后,键入go_app1应该更改您的目录。

Would a search through the bash command-history be a good enough solution? 通过bash命令历史搜索是否是一个足够好的解决方案? I also often have to log into long directory structures, but I usually Ctrl-R through. 我还经常需要登录长目录结构,但我通常都是Ctrl-R。 Eg, if I had fairly recently cd-ed into your app1.com, I'd press Ctrl-R then type app1.com and the last command using app1.com would appear, at which point you press enter and you're done. 例如,如果我最近刚进入你的app1.com,我会按Ctrl-R然后输入app1.com,然后会出现使用app1.com的最后一个命令,此时你按Enter键就完成了。 If "cd" is not the one, you press Ctrl-R a few more times until it appears. 如果“cd”不是那个,则再按Ctrl-R几次直到它出现。

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

Of course, this works only if you're concerned with how much you type, not if you're trying to do this programmatically, and only if the "cd" command was fairly recent in the list of commands that had "app1.com" (or any other short distinguishing pattern) explicitly. 当然,这只有在你关心键入多少时才有效,而不是你想以编程方式执行此操作,并且只有“cd”命令在具有“app1.com”的命令列表中相当近。 “(或任何其他短的区别模式)明确。

I would set the $CDPATH variable (in bash ) to all the directories to be searched, including the current directory (at first), like: 我将$CDPATH变量(在bash )设置为要搜索的所有目录,包括当前目录(首先),如:

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

then I can just say: 然后我可以说:

 cd app1.com

given that, the directory names are short and I can type (rather than search them through the history) 鉴于此,目录名称很短,我可以输入(而不是通过历史记录搜索它们)

Improving on the corkin alias advice, but given flexibility of "naming" (with argument app1.com, app2.com, ...), this solution solves it with a single alias: 改进corkin别名建议,但考虑到“命名”的灵活性(使用参数app1.com,app2.com,...),此解决方案使用单个别名解决它:

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

afterwards, 然后,

go_app app1.com

will cd into /var/virtual/app1.com/ . cd到/var/virtual/app1.com/。 On naming: I would name it cd_app . 在命名时:我会将其命名为cd_app On a side note go_app without arguments will kick you back to your home (because the last command is cd without further arguments). go_app没有参数的go_app会将你带回家(因为最后一个命令是没有进一步参数的cd )。

Add this in your .bashrc : 在你的.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')
}

This will create functions go_appX with X a number such that the directory /var/virtual/appX.com exists, and this function, when called, will just cd into that directory. 这将创建带有X的函数go_appX ,使得目录/var/virtual/appX.com存在,并且该函数在被调用时将只是cd进入该目录。

Look (don't worry, I'm in a sandbox): 看(别担心,我在沙盒中):

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

Done! 完成!

If new directories are created, then just relaunch the function _make_go_apps . 如果创建了新目录,则只需重新启动函数_make_go_apps

This methods fulfills all the OP's requirements and is general enough to be able to cope with any number of directories. 这种方法满足了所有OP的要求,并且通用性足以应对任意数量的目录。

eval is evil, but used in a safe way (read with sanitized variables, even though it's useless here; but if one day you want to generalize this method, you'll at least have this part correct). eval是邪恶的,但是以安全的方式使用(使用已消毒的变量读取,即使它在这里没用;但如果有一天你想要推广这种方法,你至少会使这部分正确)。

Do not try to generalize this method unless you absolutely know what you're doing: taking care of file names containing spaces, newlines, trailing newlines, etc. 除非你完全知道自己在做什么,否则不要试图概括这个方法:处理包含空格,换行符,尾随换行符等的文件名。

Remarks. 备注。

  • If you want to change the location /var/virtual , just change the local variable r , making sure it's an absolute path. 如果要更改位置/var/virtual ,只需更改局部变量r ,确保它是绝对路径。
  • Tab completion of course works very well (and tab-tab will show you the possibilities). 选项卡完成当然非常有效(选项卡选项卡将显示可能性)。
  • If you delete some directories, you might want a _clean_go_apps to only retain the relevant go_appX . 如果删除某些目录,您可能希望_clean_go_apps仅保留相关的go_appX One possibility is (it'll go in your .bashrc ): 一种可能性是(它将进入你的.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) } 

    In this case, read the next part. 在这种情况下,请阅读下一部分。


Then you'll realize it's not a good idea to have /var/virtual in two distinct places, so you'll want to use a global variable, and you'll end up with this in your .bashrc : 然后你会发现在两个不同的地方使用/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

I marked the variable _go_apps_basedir readonly , so that it's not changed inadvertently. 我将变量_go_apps_basedir标记为readonly ,因此不会无意中更改。 This time I chose to use IFS='' and -d '' in the read, together with -printf '%f\\0' in the find command, to show you how to do safe stuff when parsing the output of find . 这次我选择在read中使用IFS=''-d '' ,以及在find命令中使用-printf '%f\\0' ,以向您展示在解析find输出时如何安全操作。


I'm still concerned about the find in the _make_go_apps function, as it's not a 100% pure bash solution. 我仍然关心find_make_go_apps功能,因为它不是一个100%的纯bash的解决方案。 Here's a 100% pure bash solution: 这是一个100%纯粹的bash解决方案:

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

Sorry for this long an messy post... I was more or less thinking while typing (not good to do!), and I never wanted to erase the previous parts, as they contain interesting stuff. 对不起 ,这个长篇大论的帖子......我或多或少地在打字时思考(不好做!),我从来没有想要删除之前的部分,因为它们包含有趣的东西。


Edit . 编辑 Now, to make this post even longer, here's the same, but that will create a go_X function for every directory X.com inside /var/virtual , such that X only contains the characters: [0-9a-zA-Z\\-\\._] . 现在,为了使这篇文章更长,这里是相同的,但是这将为/var/virtual每个目录X.com创建一个go_X函数,这样X只包含字符: [0-9a-zA-Z\\-\\._] Put this in your .bashrc : 把它放在你的.bashrc

readonly _go_apps_basedir=/var/virtual
make_go_functions() {
    local f d 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

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

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