所有由浪得虛名发布的文章

Linux下删除减号开头的文件【轉】

【原文鏈接】

http://blog.chinaunix.net/uid-21335514-id-5755653.html

【原文摘錄】

个人无意使用原因产生了一个临时文件,发现类似 “-2015testdoc”

这种文件不是使用常规或者\转移符类似的方式,需要使用类似下面的方式

rm — “-2015testdoc”

关于创建类似
touch — -2015testdoc 或 touch ./-2015testdoc 可以创建

避免’sudo echo x >’ 时’Permission denied’【轉】

【原文鏈接】

https://blog.csdn.net/hejinjing_tom_com/article/details/7767127

【原文摘錄】

避免’sudo echo x >’ 时’Permission denied’

甲: 示例
sudo echo a > 1.txt
-bash: 1.txt: Permission denied
乙: 分析:
bash 拒绝这么做,说是权限不够.
这是因为重定向符号 “>” 也是 bash 的命令。sudo 只是让 echo 命令具有了 root 权限,
但是没有让 “>” 命令也具有root 权限,所以 bash 会认为这个命令没有写入信息的权限。
丙: 解决办法。三种:
1. 利用 “sh -c” 命令,它可以让 bash 将一个字串作为完整的命令来执行,这样就可以将 sudo 的影响范围扩展到整条命令。
具体用法如下:

sudo sh -c “echo a > 1.txt”

利用bash -c 也是一样的,现在bash shell 流行。
2.  利用管道和 tee 命令,该命令可以从标准输入中读入信息并将其写入标准输出或文件中,
具体用法如下:
echo a |sudo tee 1.txt

echo a |sudo tee -a 1.txt   // -a 是追加的意思,等同于 >>

tee 命令很好用,它从管道接受信息,一边向屏幕输出,一边向文件写入。

linux 总是有一些小工具为我们考虑的很贴切!
3. 提升shell 权限。
sudo -s        //提到root 权限。提示符为#
当你觉得该退回到普通权限时,
sudo su username //退回到username 权限,提示符为$

exit 退出当前用户,回到上一层目录.

centos 提升权限: su  –

ubuntu 提升权限: sudu -s, sudo su

linux gdb的使用【轉】

【原文鏈接】

https://blog.csdn.net/qq769651718/article/details/79431691

【原文摘錄】

gdb的使用

​ gdb(GNU symbolic debugger)是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。

start           #开始调试,停在第一行代码处,(gdb)start
l               #list的缩写查看源代码,(gdb)l
b <lines>       #b: Breakpoint的简写,设置断点。(gdb) b 8 
b <func>        #b: Breakpoint的简写,设置断点。(gdb) b main
i breakpoints   #i:info 的简写。(gdb)i breakpoints
d [bpNO]        #d: Delete breakpoint的简写,删除指定编号的某个断点,或删除所有断点。断点编号从1开始递增。(gdb)d 1
​
s               #s: step执行一行源程序代码,如果此行代码中有函数调用,则进入该函数;(gdb) s
n               #n: next执行一行源程序代码,此行代码中的函数调用也一并执行。(gdb) n
​
r               #Run的简写,运行被调试的程序。如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。(gdb) r
c               #Continue的简写,继续执行被调试程序,直至下一个断点或程序结束。(gdb) c
finish          #函数结束
​
p [var]             #Print的简写,显示指定变量(临时变量或全局变量 例如 int a)的值。(gdb) p a
display [var]       #display,设置想要跟踪的变量(例如 int a)。(gdb) display a
undisplay [varnum]  #undisplay取消对变量的跟踪,被跟踪变量用整型数标识。(gdb) undisplay 1
set args            #可指定运行时参数。(gdb)set args 10 20
show args           #查看运行时参数。
q                   #Quit的简写,退出GDB调试环境。(gdb) q 
help [cmd]          #GDB帮助命令,提供对GDB名种命令的解释说明。如果指定了“命令名称”参数,则显示该命令的详细说明;如果没有指定参数,则分类显示所有GDB命令,供用户进一步浏览和查询。(gdb)help
回车                #重复前面的命令,(gdb)回车

test.c

#include <stdio.h>
int add(int a, int b)
{
    return a + b;
}
int sub(int a, int b)
{
    return a - b;
}
int mul(int a, int b)
{
    return a * b;
}
int main(void)
{
    char buf[] = "helloworld";
    int a = 3;
    int b = 5;  
    int c = 0;
    c = add(a, b);
    printf("%s a+b=%d\n", buf, c);
    c = sub(a, b);
    printf("%s a-b=%d\n", buf, c);
    c = mul(a, b);
    printf("%s a*b=%d\n", buf, c);
    return 0;
}
  • 编译的时候需要加上-g参数
gcc -o test -g test.c
gdb test

git diff,git format-patch,git apply和patch小问题三则【轉】

【原文鏈接】

https://blog.csdn.net/lezhang123/article/details/55095935?locationNum=8&fps=1

【原文摘錄】

这个文档主要是用来记录工作中遇到的git patch 相关的命令的介绍和相关常见问题的解决方案.

 

Patch文件有3中,git 给我们提供了2种patch 方案, 一是用git diff生成的标准patch,二是git format-patch生成的Git专用Patch。Linux 本身也有一个patch命令.

git diff

使用git diff 来输出2个commit 之前的不同之处来生成patch.

生成的这个patch文件就是我们修改的内容

 

git format-patch

1.将最新的一条修改记录生成patch

使用git format-patch生成的patch在文件的前面会有diff的信息,还有提交者,时间等等,仔细一看你会发现,这是个E-mail的文件,你可以直接发送它!这种patch,我们要用git am来应用。

如何直接把其他仓库的修改记录直接合入到当前仓库

例子:

git –git-dir=/home/builder2010/work/6589kk/ALPS.KK1.MP5.V1.3_EASTAEON89_WET_KK/.git format-patch -k -1 –stdout 57b1ace1| git am -3 -k

Git diff 和 git format-patch的对比.

A.兼容性:很明显,git diff生成的Patch兼容性强。如果你在修改的代码的官方版本库不是Git管理的版本库,那么你必须使用git diff生成的patch才能让你的代码被项目的维护人接受。

 

B.除错功能:对于git diff生成的patch,你可以用git apply –check 查看补丁是否能够干净顺利地应用到当前分支中;如果git format-patch 生成的补丁不能打到当前分支,git am会给出提示,并协助你完成打补丁工作,你也可以使用git am -3进行三方合并,详细的做法可以参考git手册或者《Progit》。从这一点上看,两者除错功能都很强。

 

C.版本库信息:由于git format-patch生成的补丁中含有这个补丁开发者的名字,因此在应用补丁时,这个名字会被记录进版本库,显然,这样做是恰当的。因此,目前使用Git的开源社区往往建议大家使用format-patch生成补丁。

 

git apply

git apply 可以应用使用git diff 和git format-patch生成的2种patch来打补丁.

 

使用git apply 命令之后patch文件中的修改会自动合入到对应的文件中,但是不会帮我们自动提交这个commit.

 

android1@Ubuntu:alps$ git apply 0001-mp3.patch

alps/0001-mp3.patch:30: trailing whitespace.

//zhangle add start

alps/0001-mp3.patch:32: space before tab in indent.

mimetype = “application/vnd.android.package-archive”;

warning: alps/packages/apps/Browser/src/com/android/browser/DownloadHandler.java has type 100755, expected 100644

warning: 2 lines add whitespace errors.

 

这里只有警告,表示patch已经成功应用了,可以使用git status来查看工作区的文件状态

 

android1@Ubuntu:alps$ git status

# On branch Android_S510_AI-XL_no_codec

# Changes not staged for commit:

#(use “git add <file>…” to update what will be committed)

#(use “git checkout — <file>…” to discard changes in working directory)

#

#       modified:packages/apps/Browser/src/com/android/browser/DownloadHandler.java

#       modified:packages/providers/DownloadProvider/src/com/android/providers/downloads/OpenHelper.java

#

# Untracked files:

#(use “git add <file>…” to include in what will be committed)

#

#       0001-mp3.patch

no changes added to commit (use “git add” and/or “git commit -a”)

 

如果没有什么冲突提示就直接使用git commit提交就可以了

 

如果遇到git apply的空格相关的问题,可以使用—whitespace 参数来尝试解决问题.

android1@Ubuntu:alps$ git apply –whitespace=warn 0001-mp3.patch

 

git am

 

android1@Ubuntu:alps$ git am 0001-mp3.patch

git am 会直接使用patch文件中的diff的信息,还有提交者,时间等等来自动提交,不需要我们再去提交commit

git am 必须使用的是用git format-patch 生成的patch文件来打补丁,而不能是使用git diff生成的patch.如果使用的是git diff生成的patch,会出现下面这个错误.

android1@Ubuntu:alps$ git am patch2.patch

Patch format detection failed.

 

使用补丁维护git仓库时遇到的小问题

1、包含二进制文件时的diff和apply

 

foo$ git diff HEAD^..HEAD > foobar.patch

 

bar$ git apply foobar.patch

error: cannot apply binary patch to ‘root/images/back_disabled.png’ without full index line

error: root/images/back_disabled.png: patch does not apply

git apply提示错误,无法应用补丁。是因为普通的diff格式文件是不支持二进制文件的,新增的或者发生变化的二进制文件无法在diff文件中体现。git扩展了diff使其支持二进制格式,生成补丁时指定选项–binary即可,生成的文件可以顺利的git apply。

 

$ git diff HEAD^..HEAD –binary > foobar.patch

2、git apply的空白问题

 

$ git apply foobar.patch

foobar.patch:271: trailing whitespace.

foobar.patch:465: space before tab in indent.

.paging_full_numbers a.paginate_active {

warning: squelched 1705 whitespace errors

warning: 1710 lines add whitespace errors.

看看git apply(1)手册上怎么说:

 

– -whitespace=

When applying a patch, detect a new or modified line that has whitespace errors. What are considered whitespace errors is controlled by core.whitespace configuration. By default, trailing whitespaces (including lines that solely consist of whitespaces) and a space character that is immediately followed by a tab character inside the initial indent of the line are considered whitespace errors.

 

By default, the command outputs warning messages but applies the patch. When git-apply is used for statistics and not applying a patch, it defaults to nowarn.

 

You can use different values to control this behavior:

 

nowarn — turns off the trailing whitespace warning.

 

warn — outputs warnings for a few such errors, but applies the patch as-is (default).

 

fix — outputs warnings for a few such errors, and applies the patch after fixing them (strip is a synonym — the tool used to consider only trailing whitespace characters as errors, and the fix involved stripping them, but modern gits do more).

 

error — outputs warnings for a few such errors, and refuses to apply the patch.

 

error-all — is similar to error but shows all errors.

 

git apply应用补丁时会检测空白错误,默认情况下,尾部空白,包含空白的空行,初始tab缩进之后紧跟的空白字符会被认为是错误。

处理这个错误的行为由命令行参数–whitespace或者core.whitespace配置来控制,共有5种可能的动作:

 

nowarn

关闭错误提示

 

warn

输出部分错误提示,但完整的应用补丁,不会处理错误,这是默认动作。

 

fix

输出部分错误,修正错误后应用补丁

 

error

输出部分错误,拒绝应用补丁。

 

error-all

输出全部的错误,拒绝应用补丁。

 

3、patch命令无法处理含有空白的文件名

 

$ patch p1 < foobar.patch

can’t find file to patch at input line 716

Perhaps you used the wrong -p or –strip option?

The text leading up to this was:

————————–

|diff –git a/root/images/Sorting icons.psd b/root/images/Sorting icons.psd

|new file mode 100644

|index 0000000..53b2e06

|Binary files /dev/null and b/root/images/Sorting icons.psd differ

————————–

File to patch:

Skip this patch? [y]

因为diff文件中的文件名含有空格,patch命令无法应用这样的diff补丁。应该避免使用带有特殊字符的文件名。

当然patch也无法引用二进制diff补丁,使用普通diff格式生成含有二进制文件的补丁时,patch会应用成功,但生成的二进制文件是空的。

 

4.错误: previous rebase directory .git/rebase-apply still exists but mbox given.

先执行git am –abort 在执行git am –whitespace=warn 0001-.patch

vim 打开文件末尾带有^M的解决办法【轉】

【原文鏈接】

https://blog.csdn.net/laoding1993/article/details/50722029

【原文摘錄】

一、背景
昨天写了一个expect脚本用来做 板卡的自动化测试,获取framer设备的link up/down信息 定向到log文件里面。为了方便分析和处理,使用shell 脚本处理这个log文本。
主要思路是将log中的特定行输出至新的new_log文件,对new_log文件中的词语进行拆分、比较,对设备link up/down 的状态信息进行统计。
初步写了一个shell脚本后,发现对设备的统计信息明显不对。为了测试程序,伪造了一个log文本,就是自己复制粘贴的数据;处理之后,发现统计信息没什么问题。。继续对源文件进行处理,还是有问题。百思不得其解。。。。
二:发现问题
经过伪造的log与new_log的对比分析发现,new_log文本里每行的末尾多了一个^M;利用shell鞋的分词程序发现,这个^M竟然与末尾单词是一个整体,怪不得统计信息有问题;单纯比较字符串的话,肯定是有问题的;
vim打开 new_log 的显示如下:

     CPU Normal^M
     Framer Host Link Up^M
     CPU Normal^M
     Framer Host Link Down^M

分词log如下:

CPU
Normal^M
Framer
Host
Link
Up^M

三、解决问题
发现这个问题之后,就得想办法去除^M 以及找到^M出现的原因;
经过百度,发现:

1. 在windows下的文本文件的每一行结尾,都有一个回车('\n')和换行('\r')
2. 在linux下的文本文件的每一行结尾,只有一个回车('\n');
3. 在Mac下的文本文件的每一行结尾,只有一个换行('\r');

而在linux下打开windows编辑过的文件,就会在行末尾显示^M;
这个^M的在vim下的输入是:

ctrl+v <----> ^
ctrl+m <----> M

四:解决方法
1:首先想到的字符串的替换
利用VIM的命令行输入:

%s/^M$//g

解释:% 指匹配整个文件,s 是置换的意思,^M 注意要用 Ctrl + V Ctrl + M 来输入,M 后面的 $ 代表匹配行尾的内容,最后的 g 则表示每行中匹配到的内容都要置换;
2:dos2unix工具

dos2unix Filename

3:批量转换

find ./ -type f -print0 | xargs -0 dos2unix

或者

find ./ -type f print0 | xargs -0 sed -i 's/^M$//'

即可。
五:后记
找到了解决方法,问题自然很快就解决啦。目前自动化脚本运行非常良好。分析结果,很直观。不过,这只是查找问题的第一步。
BTW,昨天是元宵节,解决完这个问题就直接回去了,今天补充的昨天的记录。

[SIMKAI.ttf] cannot be found

環境:

Linux Mint 17 Qiana

文件路径为:

/usr/share/texlive/texmf-dist/tex/latex/ctex/fontset/ctex-xecjk-winfonts.def
文件内容(修改后):

% ctex-xecjk-winfonts.def: Windows 的 xeCJK 字体设置,默认为六种中易字体
% vim:ft=tex

\setCJKmainfont[BoldFont={SimHei},ItalicFont={KaiTi}]{SimSun}
\setCJKsansfont{SimHei}
\setCJKmonofont{FangSong}

%\setCJKmainfont[BoldFont={SimHei},ItalicFont={[SIMKAI.TTF]}]
% {SimSun}
%\setCJKsansfont{SimHei}
%\setCJKmonofont{[SIMFANG.TTF]}

\setCJKfamilyfont{zhsong}{SimSun}
\setCJKfamilyfont{zhhei}{SimHei}
\setCJKfamilyfont{zhkai}{[SIMKAI.TTF]}
\setCJKfamilyfont{zhfs}{[SIMFANG.TTF]}
% \setCJKfamilyfont{zhli}{LiSu}
% \setCJKfamilyfont{zhyou}{YouYuan}

\newcommand*{\songti}{\CJKfamily{zhsong}} % 宋体
\newcommand*{\heiti}{\CJKfamily{zhhei}} % 黑体
\newcommand*{\kaishu}{\CJKfamily{zhkai}} % 楷书
\newcommand*{\fangsong}{\CJKfamily{zhfs}} % 仿宋
% \newcommand*{\lishu}{\CJKfamily{zhli}} % 隶书
% \newcommand*{\youyuan}{\CJKfamily{zhyou}} % 幼圆

\endinput

在ubuntu中安装中文字体【轉】

【鏈接】

https://blog.csdn.net/zapperstab/article/details/18602969

【摘錄】

1、先从你本机 C:\Windows\Fonts 拷贝或者网络上下载你想要安装的字体文件(*.ttf文件)到/usr/share/fonts/chinese/TrueType 目录下(如果系统中没有此目录,则自行mkdir创建,亦可重命名为自己喜欢的文件夹名。如果是ttc文件,请改后缀为ttf)

2、修改字体文件的权限,使root用户以外的用户也可以使用

# cd /usr/share/fonts/chinese/TrueType
# chmod 755 *.ttf

3、建立字体缓存

# mkfontscale (如果提示 mkfontscale: command not found,则需要安装# sudo apt-get install ttf-mscorefonts-installer)
# mkfontdir
# fc-cache -fv (如果提示 fc-cache: command not found,则需要安装# sudo apt-get install fontconfig)

跟我一起写shell补全脚本【轉】

【鏈接】

http://www.techug.com/post/write-shell-bash-completion-script.html

【內容】

如果你是一个重度shell用户,一定会关注所用的shell的补全功能。某款shell的补全强弱,也许就是决定你的偏好的第一要素。

shell里面补全的影子无处不在,输入命令的时候可以有补全,敲打选项的时候可以有 补全,选择文件的时候可以有补全。有些shell甚至支持通过补全来切换版本控制的分支。由于shell里面可以运行的程序千差万别,shell一般不会 内置针特定对某个工具的补全功能。与之相对的,shell提供了一些补全用的API,交由用户编写对应的补全脚本。

在这里,我想向大家介绍如何利用提供的API,来编写一个shell补全脚本。由于需 要覆盖的内容较多,所以分为Bash和Zsh两篇。也许有fish用户会抱怨,fish又一次被忽略了:D。之所以只有Bash和Zsh的内容,是因 为:1. 这两种shell的用户占了shell用户的绝大多数。2. 我没有用过fish,所以对这方面也不了解。希望有人能够锦上添花,写一个fish版本的补全脚本教程。

既然想要写一个shell补全脚本,那么接下来要决定待补全的对象了。这里我选择pandoc作为目标。pandoc是文档转换器中的瑞士军刀,支持主流的各种标记语言,甚至对于PDF和MS Word也有一定程度上的支持。pandoc支 持的选项琳琅满目,如果都要实现确实很花时间。所以这里就只实现General options,Reader options,General writer options大部分的内容。不管怎么说,这将会是一个“既不至于简单到让人丧失兴趣,又不至于困难到让人丧失信心”的任务。

安装pandoc的方式见官网上的说明,这里就不赘述了。安装完了之后,man pandoc就能看到各个选项的说明。大体上我们需要实现以下几个目标:

  1. 支持主选项(General options)
  2. 支持子选项(Reader options/General writer options)
  3. 支持给选项提供参数值来源。比如在敲pandoc -f之后,能够补全FORMAT的内容。

好,让我们开始给pandoc写补全脚本吧!

支持主选项

先列出实现了第一阶段目标的程序:

# 以pandoc的名字保存下面的程序
_pandoc() {
    local pre cur opts
 
    COMPREPLY=()
    #pre="$3"
    #cur="$2"
    pre=${COMP_WORDS[COMP_CWORD-1]}
    cur=${COMP_WORDS[COMP_CWORD]}
    opts="-f -r -t -w -o --output -v --version -h --help"
    case "$cur" in
    -* )
        COMPREPLY=( $( compgen -W "$opts" -- $cur ) )
    esac
}
complete -F _pandoc -A file pandoc

运行程序的方式:

shell$ . ./pandoc # 加载上面的程序
$ pandoc -[Tab][Tab] # 试一下补全能用不

现在我来解释下这个程序。

complete -F _pandoc -A file pandoc

是这段代码中最为关键的一行。其实该程序起什么名字都不重要,重要的是要有上面这一行。上面这一行指定bash在遇到pandoc这个词时,调用_pandoc这个函数生成补全内容。(叫_pandoc其实只是出于惯例,并不一定要在前面加下划线)。complete -F后面接一个函数,该函数将输入三个参数:要补全的命令名、当前光标所在的词、当前光标所在的词的前一个词,生成的补全结果需要存储到COMPREPLY变量中,以待bash获取。-A file表示默认的动作是补全文件名,也即是如果bash找不到补全的内容,就会默认以文件名进行补全。

假设你在键入pandoc -o sth后,连击两下Tab触发了补全,_pandoc会被执行,其中:

  1. $1的值为pandoc
  2. $2的值为sth
  3. $3的值为-o
  4. 由于COMPREPLY为空(只有cur-开头时,COMPREPLY才会被填充),所以补全的内容是当前路径下的文件名。

你应该看到了,这里我把$2$3都注释掉了。其实

pre="$3"
cur="$2"

pre=${COMP_WORDS[COMP_CWORD-1]} # COMP_WORDS变量是一个数组,存储着当前输入所有的词
cur=${COMP_WORDS[COMP_CWORD]}

是等价的。不过后者的可读性更好罢了。

最后解释下COMPREPLY=( $( compgen -W "$opts" -- $cur ) )这一行。
opts就是pandoc的主选项列表。

compgen接受的参数和complete差不多。这里它接受一个以IFS分割的字符串"$opts"作为补全的候选项(IFS即shell里面表示分割符的变量,默认是空格或者Tab、换行)。假如没有一项跟当前光标所在的词匹配,那么它返回当前光标所在的词作为结果。(也即是不补全)

实现第一个目标用到的东西就是这么多。接下来就是第二个目标了。
在继续之前,你需要把Bash文档看一遍。若能把其中的一些选项尝试一下就更好了。

支持子选项

接下来的目标是支持Reader options/General writer options。想判断是否需要补全Reader options/General writer options,先要确认输入的词里面是否有-r-f(读),以及-w-t(写)。前面提到的COMP_WORDS就派上用场了。只需要将它迭代一下,查找里面有没有我们需要确认的词。

假设我们已经确认了需要补全子选项,接下来就应该往原来的补全项中添加子选项的内容。需要补全读选项的添加读方面的选项,需要补全写选项的添加写方面的选项。既然补全选项是一个字符串,那么把要添加的字符串接到原来的opts后面就好了。这里要注意一点,假如前面的操作里面已经把某类子选项添加到opts了,那么就需要避免重复添加。

目前的实现代码如下:

_pandoc() {
    local pre cur
 
    COMPREPLY=()
    #pre="$3"
    #cur="$2"
    pre=${COMP_WORDS[COMP_CWORD-1]}
    cur=${COMP_WORDS[COMP_CWORD]}
    complete_options() {
        local opts i
        opts="-f -r -t -w -o --output -v --version -h --help"
        for i in "${COMP_WORDS[@]}"
        do
            if [ "$i" == "-f" -o "$i" == "-r" ]
            then
                opts="$opts"" -R -S --filter -p"
                break
            fi
        done
 
        for i in "${COMP_WORDS[@]}"
        do
            if [ "$i" == "-t" -o "$i" == "-w" ]
            then
                opts="$opts"" -s --template --toc"
                break
            fi
        done
        echo "$opts"
    }
 
    case "$cur" in
    -* )
        COMPREPLY=( $( compgen -W "$(complete_options)" -- $cur ) )
    esac
}
complete -F _pandoc -A file pandoc

注意跟上一个版本相比,这里把原来的opts变量替换成了complete_options这个函数的输出。通过使用函数,我们可以动态地提供补全的来源。比如我们可以在函数里列出符合特定条件的文件名,作为补全的候选词。

支持给选项提供参数值来源

好了,现在是最后一个子任务。大致浏览一下pandoc的文档,基本上就两类参数:FORMATFILE。(其它琐碎的我们就不管了,嘿嘿)

FILE好办,默认就可以补全路径嘛。那就看看FORMATFORMAT分两种,一种是读的时候支持的FORMAT,另一种是写的时候支持的FORMAT,这个把文档里面的复制一份,改改就能用了。我们把读操作支持的FORMAT叫做READ_FORMAT,相对的,写操作支持的FORMAT叫做WRITE_FORMAT

补全的来源有了,想想什么时候把它放到COMPREPLY里去。前面补全选项的时候,是通过case语句中-*来匹配的。但是这里的FORMAT参数,只在特定选项后面才有意义。所以前面一直坐冷板凳的pre变量可以上场了。

pre中存储着光标前一个词。我们就用一个case语句判断前面是否是-f-r,还是-t-w。如果符合前面两个组合之一,用compgen配合READ_FORMATWRITE_FORMAT生成补全候选词列表,一切就跟处理opts时一样。由于此时继续参与下一个判断cur的case语句已经没有意义了,这里直接让它退出函数:

READ_FORMAT="native json markdown markdown_strict markdown_phpextra 
    markdown_github textile rst html docbook opml mediawiki haddock latex"
WRITE_FORMAT="native json plain markdown markdown_strict 
    markdown_phpextra markdown_github rst html html5 latex beamer context 
    man mediawiki textileorg textinfo opml docbook opendocument odt docx 
    rtf epub epub3 fb2 asciidoc slidy slideous dzslides revealjs s5"
 
case "$pre" in
-f|-r )
    COMPREPLY=( $( compgen -W "$READ_FORMAT" -- $cur ) )
    return 0
    ;;
-t|-w )
COMPREPLY=( $( compgen -W "$WRITE_FORMAT" -- $cur ) )
    return 0
esac

. ./pandoc一下,试试看,是不是一切都ok?

诶呀,还有个问题!这次在尝试补全FORMAT的时候,还会把当前路径下的文件名补全出来。然而这并没有什么意义。所以在补全FORMAT的时候,得把路径补全关掉才行。

问题在于最后一句:complete -F _pandoc -A file pandoc。目前不管是什么情况,都会补全文件名。所以接下来得限定某些情况下才补全文件名。

第一步是移除最后一行的-A file,下一步是修改最底下的case语句,变成这样子:

case "$cur" in
-* )
    COMPREPLY=( $( compgen -W "$(complete_options)" -- $cur ) );;
* )
    COMPREPLY=( $( compgen -A file ))
esac

只有在没有找到对应的补全时,才会调用对路径的补全。

最终版本:

_pandoc() {
    local pre cur
 
    COMPREPLY=()
    #pre="$3"
    #cur="$2"
    pre=${COMP_WORDS[COMP_CWORD-1]}
    cur=${COMP_WORDS[COMP_CWORD]}
    READ_FORMAT="native json markdown markdown_strict markdown_phpextra 
    markdown_github textile rst html docbook opml mediawiki haddock latex"
    WRITE_FORMAT="native json plain markdown markdown_strict 
    markdown_phpextra markdown_github rst html html5 latex beamer context 
    man mediawiki textileorg textinfo opml docbook opendocument odt docx 
    rtf epub epub3 fb2 asciidoc slidy slideous dzslides revealjs s5"
 
    case "$pre" in
    -f|-r )
        COMPREPLY=( $( compgen -W "$READ_FORMAT" -- $cur ) )
        return 0
        ;;
    -t|-w )
        COMPREPLY=( $( compgen -W "$WRITE_FORMAT" -- $cur ) )
        return 0
    esac
 
    complete_options() {
        local opts i
        opts="-f -r -t -w -o --output -v --version -h --help"
        for i in "${COMP_WORDS[@]}"
        do
            if [ "$i" == "-f" -o "$i" == "-r" ]
            then
                opts="$opts"" -R -S --filter -p"
                break
            fi
        done
 
        for i in "${COMP_WORDS[@]}"
        do
            if [ "$i" == "-t" -o "$i" == "-w" ]
            then
                opts="$opts"" -s --template --toc"
                break
            fi
        done
        echo "$opts"
    }
 
    case "$cur" in
    -* )
        COMPREPLY=( $( compgen -W "$(complete_options)" -- $cur) )
        ;;
    * )
        COMPREPLY=( $( compgen -A file ))
    esac
}
complete -F _pandoc pandoc

最后的问题

现在补全脚本已经写好了,不过把它放哪里呢?我们需要找到这样的地方,每次启动bash的时候都会自动加载里面的脚本,不然每次都要手动加载,那可吃不消。

.bashrc是一个(不推荐的)选择,不过好在bash自己就提供了在启动时加载补全脚本的机制。

如果你的系统有这样的文件夹:/etc/bash_completion.d,那么你可以把补全脚本放到那。这样每次bash启动的时候就会加载你写的文件。

如果你的系统里没有这个文件夹,你需要查看下/etc/bash_completion这个文件。bash启动的时候,会执行. /etc/bash_completion,你可以把你的补全脚本放在这个地方。

正如许多配置文件一样,凡是有/etc版本的也对应的~/.版本。有/etc/bash_completion,自然也有~/.bash_completion。如果你只想让自己使用这个补全脚本,或者没有root权限,可以放在~/.bash_completion

Bash补全脚本的内容就是这么多……

 

详解Linux Shell命令自动补全【轉】

【鏈接】

https://blog.csdn.net/mycwq/article/details/52420330

【內容】

在Linux命令行下,输入字符后,按两次Tab键,shell就会列出以这些字符打头的所有可用命令。如果只有一个命令匹配到,按一次Tab键就自动将这个命令补全。比如,想更改密码,但只记得这个命令前几个字母是pass。这时候,按Tab键,shell就自动输出 passwd 命令,非常方便。

当然,除了命令补全,还有路径、文件名补全。这个在我们 cd 到特定目录时特别好用。

命令补全效果,如下:

那么,自己开发的程序,该怎么实现Tab自动补全?

补全命令说明

自动补全是Bash自带的一个强大的功能,允许通过编码指定命令参数如何补全。通常,补全脚本会放在/etc/bash_completion.d/ 目录下,方便统一启用所有补全脚本。
这里例子的命令为 foo
[plain] view plain copy

  1. # cat /etc/bash_completion.d/foo.bash
  2. _foo()
  3. {
  4.     local cur=${COMP_WORDS[COMP_CWORD]}
  5.     COMPREPLY=( $(compgen -W “exec help test” — $cur) )
  6. }
  7. complete -F _foo foo
如下,测试foo命令是否自动补全
[plain] view plain copy

  1. # chmod +x /etc/bash_completion.d/foo.bash
  2. # source /etc/bash_completion.d/foo.bash
  3. # foo [Tab][Tab]
  4. exec  help  test

以上,source是为了这个foo.bash在当前会话生效。默认情况下,这个补全脚本不会被执行到,也就是说,补全命令未激活。需要source激活这个脚本,就可以没有顾虑地使用了。

为了避免每次都要source一次,可以在bashrc加上这个命令。
bashrc全局配置在不同 linux 发行版可能位置不同,如下:
Centos /etc/bashrc
Ubuntu /etc/bash.bashrc
(如果只在当前帐号生效,只要配置 ~/.bashrc 即可)
在bashrc文件末尾加上 source /etc/bash_completion.d/foo.bash,这样,每次登录到linux后,就会激活这个补全脚本。

补全命令详解

前面给大家演示的例子,用到两个命令complete和compgen,下面分别介绍这两个命令。

complete (补全命令)

这是命令补全最核心的命令了,来看下这个命令的参数说明。
[plain] view plain copy

  1. # help complete
  2. complete: complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name …]

重点说明:

-F function 执行shell 函数,函数中生成COMPREPLY作为候选的补全结果
-C command 将 command 命令的执行结果作为候选的补全 结果
-G pattern 将匹配 pattern的文件名作为候选的补全结果
-W wordlist 分割 wordlist 中的单词,作为候选的补全结果
-p [name] 列出当前所有的补全命令
-r [name] 删除某个补全命令
演示下:
[plain] view plain copy

  1. # complete -W ‘word1 word2 word3 test’ foo
  2. # foo w<Tab>
  3. # foo word<Tab>
  4. # complete -p
  5. complete -W ‘word1 word2 word3 test’ foo
  6. complete -o filenames -F __udisks udisks
  7. # complete -r foo
  8. # complete -p
  9. complete -o filenames -F __udisks udisks

compgen(筛选命令)

这个命令,用来筛选生成 匹配单词的 候选补全结果
[plain] view plain copy

  1. # help compgen
  2. compgen: compgen [-abcdefgjksuv] [-o option]  [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]

重点说明:

-W wordlist 分割 wordlist 中的单词,生成候选补全列表
[plain] view plain copy

  1. # compgen -W ‘word1 word2 test’
  2. word1
  3. word2
  4. test
  5. # compgen -W ‘word1 word2 test’ word
  6. word1
  7. word2

compopt(修改补全命令设置)

这个命令可以修改补全命令设置,注意了,这个命令必须在补全函数中使用,否则会报错。
[plain] view plain copy

  1. # help compopt
  2. compopt: compopt [-o|+o option] [-DE] [name …]

重点说明:

+o option 启用 option 配置
-o option 弃用 option 配置
例如,设置命令补全后不要多加空格,方法如下:
compopt -o nospace

内置补全变量

除了上面三个命令外,Bash还有几个内置变量来辅助补全功能,如下:
COMP_WORDS 类型为数组,存放当前命令行中输入的所有单词
COMP_CWORD 类型为整数,当前输入的单词在COMP_WORDS中的索引
COMPREPLY 类型为数组,候选的补全结果
COMP_WORDBREAKS 类型为字符串,表示单词之间的分隔符
COMP_LINE 类型为字符串,表示当前的命令行输入字符
COMP_POINT 类型为整数,表示光标在当前命令行的哪个位置

命令行补全实例

下面再结合前面三个补全命令(complete/compgen/compopt)和内置变量,写了例子说明下。
[plain] view plain copy

  1. # cat /etc/bash_completion.d/foo.bash
  2. _foo()
  3. {
  4.     COMPREPLY=()
  5.     local cur=${COMP_WORDS[COMP_CWORD]};
  6.     local cmd=${COMP_WORDS[COMP_CWORD-1]};
  7.     case $cmd in
  8.     ‘foo’)
  9.           COMPREPLY=( $(compgen -W ‘help test read’ — $cur) ) ;;
  10.     ‘test’)
  11.           local pro=( $(awk ‘{print $1}’ /data/a.txt) )
  12.           COMPREPLY=( $(compgen -W ‘${pro[@]}’ — $cur) ) ;;
  13.     ‘*’)
  14.           ;;
  15.     esac
  16.     if [[ “${COMP_WORDS[1]}” == “read” && ${COMP_CWORD} -eq 2 ]]; then
  17.           local pro=($(pwd))
  18.           cd /data
  19.           compopt -o nospace
  20.           COMPREPLY=($(compgen -d -f — $cur))
  21.           cd $pro
  22.     fi
  23.     return 0
  24. }
  25. complete -F _foo foo
例子中, foo有3个参数,分别是 help, read, test
read 测试遍历 /data 目录下所有文件
test 测试从文件中提取2级参数
help 只是演示,没有特殊作用
现在跑下这个例子:
[plain] view plain copy

  1. # mkdir /data
  2. # touch /data/a.txt
  3. # touch /data/b.txt
  4. # tree /data
  5. /data
  6. ├── a.txt
  7. └── b.txt
  8. 0 directories, 2 files
  9. # source /etc/bash_completion.d/foo.bash
  10. # foo [Tab][Tab]
  11. help  read  test
  12. # echo world1 >> /data/a.txt
  13. # echo world2 >> /data/a.txt
  14. # foo test world[Tab][Tab]
  15. world1  world2
  16. # foo read[Tab][Tab]
  17. a.txt  b.txt
参考:
http://blog.csdn.net/mycwq/article/details/52420330
https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
http://kodango.com/bash-competion-programming
http://unix.stackexchange.com/questions/55520/create-bash-completion-script-to-autocomplete-paths-after-is-equal-sign
https://devmanual.gentoo.org/tasks-reference/completion/index.html