解决 oh-my-zsh 中文乱码

今天尝试使用 oh-my-zsh,按照 github 上的说明:

curl -L http://install.ohmyz.sh | sh

进行安装完成后,运行 ls 发现中文文件名是乱码。搜索了一番,在 ~/.zshrc 文件末尾加入下面两行:

export LC_ALL=en_US.UTF-8  
export LANG=en_US.UTF-8

重启终端,或者运行

source ~/.zshrc

就 OK 了。

使用 Shell 花括号展开

我们先来简单看下,什么是 Shell 花括号展开,在终端输入如下内容回车:

$ echo {1..5}
1 2 3 4 5

可以看到 {1..5} 被 Shell 展开为 1 2 3 4 5,我们再来看几个例子:

$ echo person_{1..5}
person_1 person_2 person_3 person_4 person_5

$ echo hello_{1..5}_word
hello_1_word hello_2_word hello_3_word hello_4_word hello_5_word

接下来是一个带有多个 {} 的例子:

$ echo a{1..5}b{3..6}c
a1b3c a1b4c a1b5c a1b6c a2b3c a2b4c a2b5c a2b6c a3b3c a3b4c a3b5c a3b6c a4b3c a4b4c a4b5c a4b6c a5b3c a5b4c a5b5c a5b6c

Shell 会根据 {} 的个数产生其笛卡尔积个串。{} 里面不仅可以由 .. 来表示一个序列中任一个字符,也可以使用逗号表示其列表中任一个字符,看这个例子:

$ echo a{1,8,b}c
a1c a8c abc

OK, 这就是 Shell 花括号展开式的作用啦,下面我们来看一个实际应用场景。

有这样一个需求,我们需要在一张数据表里面构造一些数据,假设是一张成绩表(users),分别有语文(chinese),数学(math),英语(english),这三个字段。手动往数据库里面当然是可以做到的,但是太费时间,用 PHP 写个循环插多条记录也比较快,但是至少还是得需要十几行代码,需要连数据库啊,需要在循环体里面插记录啊。这种情况 Shell 的花括号展开就可以派上用场啦。我们先写插入一条记录的 SQL:

insert user (chinese,math,english) values (80, 90, 70);

然后这样:

$ echo "insert user (chinese,math,english) values ("{80..90}", "{70..98}", "{68,70}");"

就会输出多条插入语句,在 MySQL 里面运行一下就 OK 啦。

有空多学一下这些技巧,虽然前期需要花点时间学习,但是一旦学会使用后在以后的工作中可以节约大量时间。

最近在看《The Linux Comand Line》这本书,这是一本开源的讲 Linux 命令行的书。以前都是用到什么看下手册或者在网上搜下,没有系统的学习过,书里面的内容大部分比较清楚(本人命令还算用得比较熟练啦),这两天感觉最大的收获就是知道了 Shell 花括号展开这个神器。

终端输入 Shell 命令时可用的快捷键

编辑命令:

  1. Ctrl – a 移动光标到行首
  2. Ctrl – e 移动光标到行尾
  3. Ctrl – l 清屏(功能同 clear 命令)
  4. Ctrl – d 删除光标所在位置的字符
  5. Ctrl – t 光标所在位置的字符和其前面的字符进行交换
  6. Ctrl – k 剪切从光标所在位置到行尾的字符
  7. Ctrl – u 剪切从光标所在位置到行首的字符
  8. Ctrl – y 粘贴由上两个命令删除的字符到当前光标所在位置

搜索命令:

  1. Ctrl – r 搜索历史命令
  2. Ctrl – j 搜索到后,按 Ctrl – j 可以将命令复制当前命令行

命令历史展开:

  1. !! 重复执行上一次的命令,和先按方向键上然后回车效果一样
  2. !number 重复执行指定 number 的历史命令
  3. !string 重复执行以 string 开头的历史命令
  4. !?string 重复执行包含 string 的历史命令

bash启动脚本

本文系转载,原文网址:http://learn.akae.cn/media/ch31s04.html

4. bash启动脚本

启动脚本是bash启动时自动执行的脚本。用户可以把一些环境变量的设置和alias、umask设置放在启动脚本中,这样每次启动Shell时这些设置都自动生效。思考一下,bash在执行启动脚本时是以fork子Shell方式执行的还是以source方式执行的?

启动bash的方法不同,执行启动脚本的步骤也不相同,具体可分为以下几种情况。

4.1. 作为交互登录Shell启动,或者使用–login参数启动

交互Shell是指用户在提示符下输命令的Shell而非执行脚本的Shell,登录Shell就是在输入用户名和密码登录后得到的Shell,比如从字符终端登录或者用telnet/ssh从远程登录,但是从图形界面的窗口管理器登录之后会显示桌面而不会产生登录Shell(也不会执行启动脚本),在图形界面下打开终端窗口得到的Shell也不是登录Shell。

这样启动bash会自动执行以下脚本:

首先执行/etc/profile,系统中每个用户登录时都要执行这个脚本,如果系统管理员希望某个设置对所有用户都生效,可以写在这个脚本里

然后依次查找当前用户主目录的~/.bash_profile、~/.bash_login和~/.profile三个文件,找到第一个存在并且可读的文件来执行,如果希望某个设置只对当前用户生效,可以写在这个脚本里,由于这个脚本在/etc/profile之后执行,/etc/profile设置的一些环境变量的值在这个脚本中可以修改,也就是说,当前用户的设置可以覆盖(Override)系统中全局的设置。~/.profile这个启动脚本是sh规定的,bash规定首先查找以~/.bash_开头的启动脚本,如果没有则执行~/.profile,是为了和sh保持一致。

顺便一提,在退出登录时会执行~/.bash_logout脚本(如果它存在的话)。

4.2. 以交互非登录Shell启动

比如在图形界面下开一个终端窗口,或者在登录Shell提示符下再输入bash命令,就得到一个交互非登录的Shell,这种Shell在启动时自动执行~/.bashrc脚本。

为了使登录Shell也能自动执行~/.bashrc,通常在~/.bash_profile中调用~/.bashrc:

if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

这几行的意思是如果~/.bashrc文件存在则source它。多数Linux发行版在创建帐户时会自动创建~/.bash_profile和~/.bashrc脚本,~/.bash_profile中通常都有上面这几行。所以,如果要在启动脚本中做某些设置,使它在图形终端窗口和字符终端的Shell中都起作用,最好就是在~/.bashrc中设置。

下面做一个实验,在~/.bashrc文件末尾添加一行(如果这个文件不存在就创建它):

export PATH=$PATH:/home/akaedu

然后关掉终端窗口重新打开,或者从字符终端logout之后重新登录,现在主目录下的程序应该可以直接输程序名运行而不必输入路径了,例如:

~$ a.out

就可以了,而不必

~$ ./a.out

为什么登录Shell和非登录Shell的启动脚本要区分开呢?最初的设计是这样考虑的,如果从字符终端或者远程登录,那么登录Shell是该用户的所有其它进程的父进程,也是其它子Shell的父进程,所以环境变量在登录Shell的启动脚本里设置一次就可以自动带到其它非登录Shell里,而Shell的本地变量、函数、alias等设置没有办法带到子Shell里,需要每次启动非登录Shell时设置一遍,所以就需要有非登录Shell的启动脚本,所以一般来说在~/.bash_profile里设置环境变量,在~/.bashrc里设置本地变量、函数、alias等。如果你的Linux带有图形系统则不能这样设置,由于从图形界面的窗口管理器登录并不会产生登录Shell,所以环境变量也应该在~/.bashrc里设置。

4.3. 非交互启动

为执行脚本而fork出来的子Shell是非交互Shell,启动时执行的脚本文件由环境变量BASH_ENV定义,相当于自动执行以下命令:

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

如果环境变量BASH_ENV的值不是空字符串,则把它的值当作启动脚本的文件名,source这个脚本。

4.4. 以sh命令启动

如果以sh命令启动bash,bash将模拟sh的行为,以~/.bash_开头的那些启动脚本就不认了。所以,如果作为交互登录Shell启动,或者使用–login参数启动,则依次执行以下脚本:

/etc/profile
~/.profile

如果作为交互Shell启动,相当于自动执行以下命令:

if [ -n "$ENV" ]; then . "$ENV"; fi

如果作为非交互Shell启动,则不执行任何启动脚本。通常我们写的Shell脚本都以#! /bin/sh开头,都属于这种方式。