Tag: shell

shell记录

多行复制

1
2
3
4
9,14 copy 45 # copy
9,14 move 45 # move
9,14 m 45 # move

粘贴到行首

使用大写 P

在某个目录下查找包含某个字符串的文件

1
find . | xargs grep -ri "some string"

xargs命令

作用:将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。

1
2
3
4
5
6
7
rm `find /path -type f`
# 如果path目录下文件过多就会因为“参数列表过长”而报错无法执行。但改用xargs以后,问题即获解决。
find /path -type f -print0 | xargs -0 rm
# xargs将find产生的长串文件列表拆散成多个子串,然后对每个子串调用rm。

查找指定时间范围的文件

1
find ./*.jpg -newermt "2013-10-28" ! -newermt "2013-10-29"

字符串参与条件判断或者计算时,必须加上双引号

1
2
3
4
5
if [ -n "$string" ];
string="test test2"
your_func $string # 错误:函数会接收到两个参数
your_func "$string" # 正常:函数正常接收到一个参数

注意: shell会把字符串按照IFS进行分割处理

多行字符串:IFS换行符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ifs=$IFS
IFS=$`\n` # 注意这里,不能使用: IFS="\n" or IFS='\n'
config=`cat <<EOF
output: .user.js
dese:
// ==UserScript==
// @name Userscript
// @namespace http://cyy0523xc.github.io/
// @version 0.1
// @description something
// @match http://*/*
// @copyright 2014, Alex(cyy0523xc@gmail.com)
// ==/UserScript==
input:
-
EOF`
echo $config
IFS=$ifs

批量重命名文件

1
rename 's/201[34]\-[01][0-9]\-[012][0-9]\-//' *.md

期待一元表达式

异常信息:

1
bash: [: h: 期待一元表达式]

对应语句:

1
2
3
4
5
if [ "h" = $1 ]
# 如果变量未定义的话,则报错,应改成:
if [ "h" = "$1" ]

shell-export及执行环境

export 功能说明:设置或显示环境变量。

语  法:export [-fnp] [变量名称]=[变量设置值]

补充说明:

  • 在shell中定义的变量,通常只能在当前shell中有效,只有用export输出之后,才能在其fork的子shell中有效。
  • 子shell中的变量无法被父shell读取,即使export也不行。

参  数:

  • -f  代表[变量名称]中为函数名称。
  • -n  删除指定的变量。变量实际上并未删除,只是不会输出到后续指令的执行环境中。
  • -p  列出所有的shell赋予程序的环境变量。

用法:

1
2
3
4
export var
export -f func
export -fp

shell的命令类型

1. 内置命令(Builtin)

shell 执行这些命令时不会派生新进程,而是由 shell 直接执行。比如 read, set, export 都是内置命令,这些命令需要用 help command 来查看其帮助信息。

2. 外部命令

外部命令就是普通的可执行二进制文件,shell 在执行它们时会 fork 出新进程(这是一个子 shell),然后用 exec 系列函数来执行它们,这时候子 shell 的环境就被命令的环境所取代。

3. shell 脚本

在执行 shell 脚本时,shell 同样会先执行 fork 派生出子进程,然后使用 exec 来调用脚本解释程序(内核中会检查脚本中的第一行 #!/bin/xxx 来确定是调用哪一种),然后将脚本装入,由它来解释执行。脚本解释器有很多,比如 bash, cshell, perl, python 等。如果被调出来的解释程序和当前 shell 是同一种 shell,那么它就是当前 shell 的子 shell,脚本中的命令都在子 shell 中执行,不会影响父 shell 的环境。

几种常见的形式

( ) 和 { } 中的指令组:

在 ( ) 和 { } 中都可以内置一组指令。
( ) 中的指令会在一个子 shell 中执行,命令执行结果不影响当前 shell。需要注意的是,$$ 代表当前 shell 进程的 PID,而不是子 shell 进程的 PID 。

{ } 中的指令在当前 shell 中执行,指令执行结果会影响当前的环境。

后台执行和异步执行

在一个 shell 脚本中将一个命令通过 & 放入后台执行,这个命令和当前 shell 的执行是并行的,当前 shell 会派生一个子 shell 执行这个后台命令,而自己则继续往下执行,两者并没有相互依赖及等待的关系,所以这是一种异步的执行方式。以下代码可以说明这一点:

命令替换

`command` 会将 command 命令的输出结果代换到当前的命令行。command 在子 shell 中执行,它的结果不会影响到当前 shell 。比较下面代码:

1
2
3
4
pwd
dir=`cd /tmp; pwd`
echo $dir
pwd

管道

对于 bash 来说(dash,ash 等大部分 shell 也一样), 管道中的命令都是放在子shell里执行的

1
2
3
4
5
6
a="hello world"
echo "$a"| (read var; echo "In subshell:$var")
# 管道中的命令是放在子 shell 里执行的,所以 var 得到的值无法传递到当前 shell ,所以这里要输出为空。
echo $var

相关资料

shell命令自动补全

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# github相关操作
github() {
cd_github_code
my_github=git@github.com/cyy053xc/
case $1 in
"c"|"clone")
git clone $my_github$2".git"
;;
"l"|"pull")
pushd $my_github$2
git pull
popd
;;
"s"|"push")
pushd $my_github$2
git pull
git commit -am 'script commit'
git push
popd
;;
"h"|"help"|*)
cat <<EOF
github [hcls] [path]
usage:
h|help : help
c|clone project : git clone {$my_github}project.git
l|pull project : git pull
s|push project : git push
EOF
;;
esac
}
# 补全函数
function _github() {
COMPREPLY=()
local cur=${COMP_WORDS[COMP_CWORD]};
local com=${COMP_WORDS[COMP_CWORD-1]};
case $com in
'github')
COMPREPLY=($(compgen -W 'c clone l pull s push h help' -- $cur))
;;
'compile')
local pro=($(awk '{print $1}' project.list))
COMPREPLY=($(compgen -W '${pro[@]}' -- $cur))
;;
*)
;;
esac
return 0
}
# 绑定自动补全函数
complete -F _github github

从效果上,可以说已经实现了tab键自动补全,不过不是很完美:

  • 每个函数需要搭配一个额外的补全函数
  • 补全函数的实现有大量的重复代码
  • 另外还需要一个额外的命令进行绑定

理想的应该是:在函数的内部加上一条命令或者一个配置来解决。