bash knack - hanyong/note GitHub Wiki

bash 小技巧

修改 xterm 终端标题

可使用特殊 xterm 序列修改终端标题, 参考: http://tldp.org/HOWTO/Xterm-Title-3.html

* ESC]0;stringBEL -- Set icon name and window title to string
* ESC]1;stringBEL -- Set icon name to string
* ESC]2;stringBEL -- Set window title to string

where ESC is the escape character (\033), and BEL is the bell character (\007). 

参考 ubuntu 默认的做法, 是将此特殊序列添加到 $PS1 变量头部, 每次输出 PS1 时自动设置和更新终端标题。 对未进行此设置的系统, 按照 PS1 转义序列的写法, 在 /etc/bashrc.bashrc 末尾添加如下内容即可:

PS1='\[\e]0;\u@\h:\w\a\]'"${PS1}"

参考上述说明, 如果只修改标题, 可将 0 改成 2

sed -r -e $'$ a\\n''PS1='''\[\e]2;\u@\h:\w\a\]'''"${PS1}"' -e '/^PS1='''\[\e][0-2];.*?\a\]'''"${PS1}"/ d' ~/.bashrc -i

重新进入当前目录

cd .

当前目录被删除重建后, 当前目录信息不再有效, 如 ls 报错或看不到文件, cd . 重新进入当前目录后解决此问题.

列举隐藏文件

清空当前文件夹:

rm -rf * .[^.]*

列出当前目录文件, 忽略部分文件

find -maxdepth 1 -name . -o -name .git -o -name vendor -o -print

一个稍微简化的方法是:

ls -A | grep -Fwv -e .git -e vendor


>但当这样会使局部匹配的文件也被排除.

可封装成脚本 `lsno`:

```sh
#!/bin/bash
# 列出当前目录文件, 但排除参数列表指定的文件

a=( find -maxdepth 1 -name . )
for e in "${@}" ; do
	# basename transform ".git/" or "./.git/" to "git"
	a=( "${a[@]}" -o -name "$(basename "${e}")" )
done
a=( "${a[@]}" -o -print )
exec "${a[@]}"

ls 命令原生支持 --hide 选项,但只在列出目录子项时生效,与 -a, -A 使用时无效,对参数输入项无效。

       --hide=PATTERN
              do not list implied entries matching shell PATTERN (overridden by -a or -A)

打印调试信息

bash -x a.sh
env SHELLOPTS=xtrace xxx

启动 bash 前设置 SHELLOPTS 显式打开 set 设置项, 并且能递归到子进程. 启动 bash 后对应值为所有开启的设置项.

$ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor

$ SHELLOPTS=xtrace bash -c 'echo $SHELLOPTS'
bash: SHELLOPTS: 只读变量
braceexpand:hashall:interactive-comments

$ env SHELLOPTS=xtrace bash -c 'echo $SHELLOPTS'
+ echo braceexpand:hashall:interactive-comments:xtrace
braceexpand:hashall:interactive-comments:xtrace
```

相似的 `BASHOPTS` 对应 `shopt` 设置项.

## 字符串数组拼接

参考: http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array

bash 扩展 `"${argv[*]}"` 时会使用 `IFS` 的第一个字符进行拼接,
利用这个特性可修改 `IFS` 实现字符串数组拼接。
为了不影响 bash 的正常功能, 应该只在实现拼接的局部范围内修改 `IFS`, 可使用函数或子 shell 限制修改 IFS 的范围.

```
$ x=( a b c )
$ echo $( IFS=, && echo "${x[*]}" )
a,b,c
```

> **注意** : `IFS` 是由 bash 识别和实现, 而不是 echo。要在 bash 中修改 `IFS`, `IFS=,` 要独立成一个语句.

也可以直接调用 `bash -c`, 因为数组型变量不能直接使用环境变量传递, 可使用命令行参数传递.

```
$ bash -c 'IFS=, && echo "$*"' -c a b c
a,b,c
```

另一个办法是使用 `printf` 命令,
当 `printf` 的实际参数个数多于格式化字符串参数个数时, 会循环复用格式化字符串。
因此, 格式化字符串只有一个参数, 即可应用于所有实际参数.

```
$ x=$(printf "%s," a b c)
$ echo "${x::-1}"
a,b,c
```