Fork me on GitHub
Suzf  Blog

Archive Linux

How-to find MySQL process list and to kill those processes

有些时候由于MySQL 表和查询设计的不够好,常常以为一个SQL是这个数据库卡住亦或是查询变得灰常的慢。

那么我们该如何查到查询列表并杀死它们呢?

 

Here I go with solution.

  1. Login to DB.
  2. run command show full processlist;
  3. Here you will get the process id with status and Query it self which causing the problem of hanging database.
  4. Now select the process id and run command KILL <pid>;
  5. Now that point you kill that process.

Sometime that is not enough to kill each process manually. So, for that we've to go with some sort of trick. here I go with that trick:

  1. Login to MySql
  2. run that query Select concat('KILL ',id,';') from information_schema.processlist where user='user';
  3. This will print all the process with KILL command.
  4. Copy all the query result, manipulate them and remove pipe | sign and paste all again into the query console. HIT ENTER. BooM its done.

相关连接

[0] https://dev.mysql.com/doc/refman/5.7/en/kill.html

[1] https://stackoverflow.com/questions/44192418/how-to-find-mysql-process-list-and-to-kill-those-processes

[2] https://stackoverflow.com/questions/1903838/how-do-i-kill-all-the-processes-in-mysql-show-processlist

MongoDB 基本查询

MongoDB 基本查询

数据库版本
> db.version()
3.0.6

1. show dbs
查看当前主机的所有数据库

db
查看当前所使用的数据库

show collections
查看当前数据库的 collection == show tables

** 如何查看帮助 **
> help

如果想知道当前数据库支持哪些方法
> db.help();

如果想知道当前数据库下的表或者表collection支持哪些方法,可以使用一下命令如:
> db.user.help(); user为表名

2. use cherry
切换数据库, 如果数据库不存在则新创建数据库[ 隐示创建数据库 ]

3. db.user.save({"name":"jack", age:21, "sex":"male"});
user这个表也会隐式的被创建,并且插入一条文档 ,文档有name,age,sex。下面我们在用另外一种方法插入一条数据。

删除表
> db.user.drop();
True

4. db.user.insert({"name":"tom", age:19, "sex":"male"});
在user中插入数据,可能你会问insert和save有什么不同,他们还真的有点不同!
insert仅仅是插入文档到集合中,如果记录不存在则插入,如果记录存在则忽略

** save是在文档不存在时插入,存在时则是更新 **

5. db.user.find();
这个可以查询user集合中所有的数据。所有的文档都有_Id这一列,这个是主键,是系统生成唯一的主键,不过我们也可以自己来操作,不过自己操作的时候可千万不能有重复的值,要不会有异常。

6. db.user.findOne();
这个查询user集合中最上面一条数据并显示。

7. db.user.find({name:"jack"});
查询name是jack的文档。

8. db.user.update({name:"tom"}, {$set:{name:"Jim"}});
修改名称tom为Jim,这个是修改的方法。

9. db.user.remove({name:"Jim"});
这个是删除name为Jim!
这些都是最最基本的增删改查了,下面将重点讲解查询!

10. 条件操作符< 、<=、>、>=
db.user.find({age:{$gt:20}});
查询年龄大于12岁的用户,如此的还有$lt小于、$gte大于等于、$lte小于等于。

11. $all匹配所有
db.user.find({age:{$all:[21]}});
他会匹配所有age等于21的文档。

12. $exists判断字段是否存在
db.user.find({age:{$exists:true}});
查询所有存在age字段的文档。false表示不存在。

13. $mod取模运算
db.user.find({age:{$mod:[10, 1]}});
查询所有age模10等于1的文档。

14. $ne不等于
db.user.find({age: {$ne : 20}});
查询所有年龄不等于20的用户文档。

15. $in包含
db.user.find({age : { $in : [20, 21, 22]}});
查询所有年龄等于20、21、22的用户文档。

16. $nin不包含
db.user.find({age : {$nin : [20, 21, 22]}});
查询所有年龄不等于20、21、22的用户文档。

17. count查询记录条数
db.user.find().count();
返回cherry集合中文档记录的数目。

18. limit限制显示的条数
db.user.find().limit(5);
返回cherry中上面的5条记录。

19. skip限制返回记录的起点
db.user.find().skip(3);
返回cherry中上面数第三条数据一下的所有数据

20. 分页的实现
db.user.find().skip(1).limit(5);
返回从第二条数据开始,显示5条数据,这个可以用作分页,很简单就实现了!

21. sort排序
db.user.find().sort({age:1});
所有的数据按年龄大小升序(asc)排列,既然1表示asc排列,那么-1就表示desc排列,这是真的。

22. distinct去掉重复值
db.user.find().distinct("name");
按name的重复值筛选数据。

根据条件查找数据
-----------------------
通过条件查询: db.foo.find( { x : 77 } , { name : 1 , x : 1 } )
-----------------------------
db.foo.find(...).count()
db.foo.find(...).limit(n) 根据条件查找数据并返回指定记录数
db.foo.find(...).skip(n)
db.foo.find(...).sort(...) 查找排序
db.foo.findOne([query]) 根据条件查询只查询一条数据
db.foo.getDB() get DB object associated with collection 返回表所属的库
db.foo.getIndexes() 显示表的所有索引
db.foo.group( { key : ..., initial: ..., reduce : ...[, cond: ...] } ) 根据条件分组
db.foo.mapReduce( mapFunction , reduceFunction , )
db.foo.remove(query) 根据条件删除数据
db.foo.renameCollection( newName ) renames the collection 重命名表
db.foo.save(obj) 保存数据
db.foo.stats() 查看表的状态
db.foo.storageSize() - includes free space allocated to this collection 查询分配到表空间大小
db.foo.totalIndexSize() - size in bytes of all the indexes 查询所有索引的大小
db.foo.totalSize() - storage allocated for all data and indexes 查询表的总大小
db.foo.update(query, object[, upsert_bool]) 根据条件更新数据
db.foo.validate() - SLOW 验证表的详细信息
db.foo.getShardVersion() - only for use with sharding

1. 超级用户相关:

#增加或修改用户密码

db.addUser('admin','pwd')

#查看用户列表

db.system.users.find()

#用户认证

db.auth('admin','pwd')

#删除用户

db.removeUser('mongodb')

#查看所有用户

show users

#查看所有数据库

show dbs

#查看所有的collection

show collections

#查看各collection的状态

db.printCollectionStats()

#查看主从复制状态

db.printReplicationInfo()

#修复数据库

db.repairDatabase()

#设置记录profiling,0=off 1=slow 2=all

db.setProfilingLevel(1)

#查看profiling

show profile

#拷贝数据库

db.copyDatabase('mail_addr','mail_addr_tmp')

#删除collection

db.mail_addr.drop()

#删除当前的数据库

db.dropDatabase()

2. 客户端连接

/usr/local/mongodb/bin/mongo user_addr -u user -p 'pwd'

3. 增删改

#存储嵌套的对象

db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})

#存储数组对象

db.user_addr.save({'Uid':'[email protected]','Al':['[email protected]','[email protected]']})

#根据query条件修改,如果不存在则插入,允许修改多条记录

db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)

#删除yy=5的记录

db.foo.remove({'yy':5})

#删除所有的记录

db.foo.remove()

4. 索引

增加索引:1(ascending),-1(descending)

db.things.ensureIndex({firstname: 1, lastname: 1}, {unique: true});

#索引子对象

db.user_addr.ensureIndex({'Al.Em': 1})

#查看索引信息

db.deliver_status.getIndexes()

db.deliver_status.getIndexKeys()

#根据索引名删除索引

db.user_addr.dropIndex('Al.Em_1')

5. 查询

查找所有

db.foo.find()

#查找一条记录

db.foo.findOne()

#根据条件检索10条记录

db.foo.find({'msg':'Hello 1'}).limit(10)

#sort排序

db.deliver_status.find({'From':'[email protected]'}).sort({'Dt',-1})

db.deliver_status.find().sort({'Ct':-1}).limit(1)

#count操作

db.user_addr.count()

#distinct操作

db.foo.distinct('msg')

#>操作

db.foo.find({"timestamp": {"$gte" : 2}})

#子对象的查找

db.foo.find({'address.city':'beijing'})

6. 管理

查看collection数据的大小

db.deliver_status.dataSize()

#查看colleciont状态

db.deliver_status.stats()

#查询所有索引的大小

db.deliver_status.totalIndexSize()

 

MongoDB 数据备份与还原

mongodb数据备份和还原主要分为二种:
一种是针对于库的mongodump和mongorestore
一种是针对库中表的mongoexport和mongoimport

一. mongodump备份数据库

1. 常用命令格

mongodump -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -o 文件存在路径

如果没有用户谁,可以去掉-u和-p。
如果导出本机的数据库,可以去掉-h。
如果是默认端口,可以去掉--port。
如果想导出所有数据库,可以去掉-d。

2. 导出所有数据库

#mongodump -h 127.0.0.1 -o /home/zfsu/mongodb/
2015-10-13T16:00:46.585+0800    writing cherry.counters to /home/zfsu/mongodb/cherry/counters.bson
2015-10-13T16:00:46.586+0800    writing cherry.counters metadata to /home/zfsu/mongodb/cherry/counters.metadata.json
2015-10-13T16:00:46.588+0800    done dumping cherry.counters (1 document)
2015-10-13T16:00:46.588+0800    writing cherry.reports to /home/zfsu/mongodb/cherry/reports.bson
2015-10-13T16:00:46.644+0800    writing cherry.reports metadata to /home/zfsu/mongodb/cherry/reports.metadata.json
2015-10-13T16:00:46.645+0800    done dumping cherry.reports (7934 documents)
... ...

3. 导出指定数据库

#mongodump -h 127.0.0.1 -d cherry -o /home/zfsu/mongodb/
2015-10-13T16:03:42.508+0800    writing cherry.counters to /home/zfsu/mongodb/cherry/counters.bson
2015-10-13T16:03:42.509+0800    writing cherry.counters metadata to /home/zfsu/mongodb/cherry/counters.metadata.json
2015-10-13T16:03:42.510+0800    done dumping cherry.counters (1 document)
2015-10-13T16:03:42.510+0800    writing cherry.reports to /home/zfsu/mongodb/cherry/reports.bson
2015-10-13T16:03:42.550+0800    writing cherry.reports metadata to /home/zfsu/mongodb/cherry/reports.metadata.json
2015-10-13T16:03:42.550+0800    done dumping cherry.reports (7934 documents)
2015-10-13T16:03:42.550+0800    writing cherry.system.indexes to /home/zfsu/mongodb/cherry/system.indexes.bson
2015-10-13T16:03:42.552+0800    writing cherry.users to /home/zfsu/mongodb/cherry/users.bson
2015-10-13T16:03:42.553+0800    writing cherry.users metadata to /home/zfsu/mongodb/cherry/users.metadata.json
2015-10-13T16:03:42.554+0800    done dumping cherry.users (35 documents)

二. mongorestore还原数据库

1. 常用命令格式
mongorestore -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 --drop 文件存在路径
--drop的意思是,先删除所有的记录,然后恢复。

2. 恢复所有数据库到mongodb中
# mongorestore /home/zfsu/mongodb/   #这里的路径是所有库的备份路径

3. 还原指定的数据库
# mongorestore -d cherry /home/zfsu/mongodb/cherry/           #cherry这个数据库的备份路径

# mongorestore -d cherry_new  /home/zfsu/mongodb/cherry/      #将cherry还有cherry_new数据库中

这二个命令,可以实现数据库的备份与还原,文件格式是json和bson的。无法指写到表备份或者还原。

三. mongoexport导出表,或者表中部分字段
1. 常用命令格式
mongoexport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表名 -f 字段 -q 条件导出 --csv -o 文件名

上面的参数好理解,重点说一下:

-f    导出指字段,以字号分割,-f name,email,age导出name,email,age这三个字段
-q    可以根查询条件导出,-q '{ "uid" : "100" }' 导出uid为100的数据
--csv 表示导出的文件格式为csv的,这个比较有用,因为大部分的关系型数据库都是支持csv,在这里有共同点

2. 导出整张表

# mongoexport -d cherry -c users -o /home/zfsu/mongodb/cherry/users.data
2015-10-13T16:19:53.048+0800    connected to: localhost
2015-10-13T16:19:53.074+0800    exported 35 records

3. 导出表中部分字段

# mongoexport -d cherry -c reports --csv -f date,tags -o /home/zfsu/mongodb/cherry/reports.csv
2015-10-13T16:23:15.269+0800    csv flag is deprecated; please use --type=csv instead
2015-10-13T16:23:15.276+0800    connected to: localhost
2015-10-13T16:23:15.477+0800    exported 7934 records

4. 根据条件导出数据

# mongoexport -d cherry -c reports -q '{time_cost:{$gt:1}}' -o /home/zfsu/mongodb/cherry/reports.json
2015-10-13T16:25:54.162+0800    connected to: localhost
2015-10-13T16:25:54.585+0800    exported 7920 records

四. mongoimport导入表,或者表中部分字段

1. 常用命令格式

1.1. 还原整表导出的非csv文件

mongoimport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表名 --upsert --drop 文件名
重点说一下--upsert,其他参数上面的命令已有提到,--upsert 插入或者更新现有数据

1.2. 还原部分字段的导出文件

mongoimport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表名 --upsertFields 字段 --drop 文件名
--upsertFields根--upsert一样

1.3. 还原导出的csv文件

mongoimport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表名 --type 类型 --headerline --upsert --drop 文件名

上面三种情况,还可以有其他排列组合的。

2. 还原导出的表数据

# mongoimport -d cherry -c users --upsert /home/zfsu/mongodb/cherry/users.data

3. 部分字段的表数据导入

# mongoimport -d cherry -c reports  --upsertFields date,tags -o /home/zfsu/mongodb/cherry/users.data

4. 还原csv文件

# mongoimport -d cherry -c reports --type csv --headerline --file /home/zfsu/mongodb/cherry/reports.csv

 

How-to: install mongo and php support

MongoDB可以从开放源代码来建构与安装,更常见的是安装binary文件,目前有Windows, Linux, OS XSolaris版本。许多Linux包管理系统现在已包含了MongoDB的包,包括CentOSFedora,[1] DebianUbuntu,[2] Gentoo[3]以及Arch Linux[4] 同样可从官方网站获取。[5]

MongoDB使用内存映射文件, 32位系统上限制大小为2GB的数据 (64-比特支持更大的数据).[6] MongoDB服务器只能用在小端序系统,虽然大部分公司会同时准备小端序和大端序系统。

Linux SSH key 登陆详解

SSH全称Secure SHell,顾名思义就是非常安全的shell的意思,SSH协议是IETF(Internet Engineering Task Force)的Network Working Group所制定的一种协议。SSH的主要目的是用来取代传统的telnet和R系列命令(rlogin,rsh,rexec等)远程登陆和远程执行命令的工具,实现对远程登陆和远程执行命令加密。防止由于网络监听而出现的密码泄漏,对系统构成威胁。

ssh协议目前有SSH1和SSH2,SSH2协议兼容SSH1。目前实现SSH1和SSH2协议的主要软件有OpenSSH和SSH Communications Security Corporation 公司的SSH Communications 软件。前者是OpenBSD组织开发的一款免费的SSH软件,后者是商业软件,因此在linux、FreeBSD、OpenBSD、NetBSD等免费类UNIX系统种,通畅都使用OpenSSH作为SSH协议的实现软件。因此,本文重点介绍一下OpenSSH的使用。需要注意的是OpenSSH和SSH Communications的登陆公钥/私钥的格式是不同的,如果想用SSH Communications产生的私钥/公钥对来登入到使用OpenSSH的linux系统需要对公钥/私钥进行格式转换。

LDAP服务器的概念和原理简单介绍

1. 目录服务

目录是一个为查询、浏览和搜索而优化的专业分布式数据库,它呈树状结构组织数据,就好象Linux/Unix系统中的文件目录一样。目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的,就好象它的名字一样。

目录服务是由目录数据库和一套访问协议组成的系统。类似以下的信息适合储存在目录中:

  • 企业员工信息,如姓名、电话、邮箱等;
  • 公用证书和安全密钥;
  • 公司的物理设备信息,如服务器,它的IP地址、存放位置、厂商、购买时间等;

How-To: Debug Crashed Linux Application Core Files Like A Pro

Core dumps are often used to diagnose or debug errors in Linux or UNIX programs. Core dumps can serve as useful debugging aids for sys admins to find out why Application like Lighttpd, Apache, PHP-CGI or any other program crashed. Many vendors and open source project author requests a core file to troubleshoot a program. A core file is generated when an application program abnormally terminates due to bug, operating system security protection schema, or program simply try to write beyond the area of memory it has allocated, and so on. This article explains how to turn on core file support and track down bugs in programs.

How-to: Linux下如何查看进程准确启动时间

在Linux下,总会有这样或是那样的需求。那么问题来了,如何查看进程的准确启动时间呢?

平时里查看进程的相关信息我通常用的是 ps aux 命令,但是ps aux命令的缺陷在于只能显示时间到年、日期、或者时间, 无法具体到年月日时分秒。如果需要查看某个进程的具体启动时间, 使用 ps -p PID -o lstart,  其中,PID为某个进程的进程ID号。
如下所示, 显示系统中所有httpd进程的具体启动时间。

[09:46:55][[email protected] ~]#for pid in $(pgrep php); do echo -n "${pid} " ; ps -p ${pid} -o lstart | grep -v "START" ; done
22527 Sat Aug 22 09:28:51 2015
22575 Sat Aug 22 09:38:50 2015
22576 Sat Aug 22 09:38:51 2015
29012 Wed Aug 19 16:11:02 2015

好了现在我们知道如何查看进程的准确启动时间了 ,下回分分钟就能搞定了 。

 

How-to: use bash_completion to complete command

如何使用 bash_completion 补全命令

对于Linuxer来说,自动补全是再熟悉不过的一个功能了。当你在命令行敲下部分的命令时,肯定会本能地按下Tab键补全完整的命令,当然除了命令补全之外,还有文件名补全。

自动补全这个功能是Bash自带的,但一般我们会安装bash-completion包来得到更好的补全效果,这个包提供了一些现成的命令补全脚本,一些基础的函数方便编写补全脚本,还有一个基本的配置脚本。但也正如之前说的,这个包不是必须的,只不过可以省些力气。

 

 

bash-completion这个包的安装位置因不同的发行版会有所区别,但是大致上启用的原理是类似的,一般会有一个名为bash_completion的脚本,这个脚本会在shell初始化时加载。例如对于RHEL系统来说,这个脚本位于/etc/bash_completion,而该脚本会由/etc/profile.d/bash_completion.sh中导入:

# Check for interactive bash and that we haven't already been sourced.
[ -z "$BASH_VERSION" -o -z "$PS1" -o -n "$BASH_COMPLETION" ] && return

# Check for recent enough version of bash.
bash=${BASH_VERSION%.*}; bmajor=${bash%.*}; bminor=${bash#*.}
if [ $bmajor -gt 3 ] || [ $bmajor -eq 3 -a $bminor -ge 2 ]; then
    if shopt -q progcomp && [ -r /etc/bash_completion ]; then
        # Source completion code.
        . /etc/bash_completion
    fi
fi
unset bash bmajor bminor

而在bash_completion脚本中会加载/etc/bash_completion.d下面的补全脚本:

if [[ $BASH_COMPLETION_DIR != $BASH_COMPLETION_COMPAT_DIR && \
    -d $BASH_COMPLETION_DIR && -r $BASH_COMPLETION_DIR && \
    -x $BASH_COMPLETION_DIR ]]; then
    for i in $(LC_ALL=C command ls "$BASH_COMPLETION_DIR"); do
        i=$BASH_COMPLETION_DIR/$i
        [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) \
            && -f $i && -r $i ]] && . "$i"
    done
fi
unset i

补全脚本的名称一般就是命令名,这样比较容易查找:

$ ls i*
iconv  iftop  ifupdown  info  iproute2  iptables

内置补全命令

Bash内置有两个补全命令,分别是compgen和complete。compgen命令根据不同的参数,生成匹配单词的候选补全列表,例如:

$ compgen -W 'hi hello how world' h
hi
hello
how

compgen最常用的选项是-W,通过-W参数指定空格分隔的单词列表。h即我们在命令行当前键入的单词,执行完后会输出候选的匹配列表,这里是以h开头的所有单词。

complete命令的参数有点类似compgen,不过它的作用是说明命令如何进行补全,例如同样使用-W参数指定候选的单词列表:

$ complete -W 'word1 word2 word3 hello' foo
$ foo w<Tab>
$ foo word<Tab>
word1  word2  word3

我们还可以通过-F参数指定一个补全函数:

$ complete -F _foo foo

现在键入foo命令后,会调用_foo函数来生成补全的列表,完成补全的功能,这一点正是补全脚本实现的关键所在,我们会在后面介绍。
补全相关的内置变量

除了上面的两个补全命令外,Bash还有几个内置的变量用来辅助补全功能,这里主要介绍其中三个:

COMP_WORDS: 类型为数组,存放当前命令行中输入的所有单词;
COMP_CWORD: 类型为整数,当前光标下输入的单词位于COMP_WORDS数组中的索引;
COMPREPLY: 类型为数组,候选的补全结果;
COMP_WORDBREAKS: 类型为字符串,表示单词之间的分隔符;
COMP_LINE: 类型为字符串,表示当前的命令行输入;

例如我们定义这样一个补全函数_foo:

$ function _foo()
> {
>     echo -e "\n"
>
>     declare -p COMP_WORDS
>     declare -p COMP_CWORD
>     declare -p COMP_LINE
>     declare -p COMP_WORDBREAKS
> }
$ complete -F _foo foo

假设我们在命令行下输入以下内容,再按下Tab键补全:

$ foo b

declare -a COMP_WORDS='([0]="foo" [1]="b")'
declare -- COMP_CWORD="1"
declare -- COMP_LINE="foo b"
declare -- COMP_WORDBREAKS="
\"'><=;|&(:"

对着上面的结果,我想应该比较容易理解这几个变量。当然正如我们之前据说,Bash-completion包并非是必须的,补全功能是Bash自带的。
编写脚本

补全脚本分成两个部分:编写一个补全函数和使用complete命令应用补全函数。后者的难度几乎忽略不计,重点在如何写好补全函数。难点在,似乎网上很少与此相关的文档,但是事实上,Bash-completion自带的补全脚本是最好的起点,可以挑几个简单的改改基本上就可以使用了。

一般补全函数(假设这里依然为_foo)都会定义以下两个变量:

local cur prev

其中cur表示当前光标下的单词,而prev则对应上一个单词:

cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"

初始化相应的变量后,我们需要定义补全行为,即输入什么的情况下补全什么内容,例如当输入-开头的选项的时候,我们将所有的选项作为候选的补全结果:

local opts="-h --help -f --file -o --output"

if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi

 

不过再给COMPREPLY赋值之前,最好将它重置清空,避免被其它补全函数干扰。

现在完整的补全函数是这样的:

function _foo() {
    local cur prev opts

    COMPREPLY=()

    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="-h --help -f --file -o --output"

    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}

 

现在在命令行下就可以对foo命令进行参数补全了:

$ complete -F _foo foo
$ foo -
-f        --file    -h        --help    -o        --output

当然,似乎我们这里的例子没有用到prev变量。用好prev变量可以让补全的结果更加完整,例如当输入--file之后,我们希望补全特殊的文件(假设以.sh结尾的文件):

case "${prev}" in
-f|--file)
COMPREPLY=( $(compgen -o filenames -W "`ls *.sh`" -- ${cur}) )
;;
esac

现在再执行foo命令,--file参数的值也可以补全了:

$ foo --file<Tab>
a.sh b.sh c.sh

 

参考链接

  1. An introduction to bash completion: part 2
  2. Writing your own Bash Completion Function
  3. Programmable Completion
  4. Completion Files