Linux内建命令

1.如何确定内建命令:type

不要试图用脑子记住所有的命令,这不可能也不需要。判断一个命令是不是内建命令只需要借助于命令type即可,如下所示:

# cd命令是内建命令
[root@banana ~]# type cd
cd is a shell builtin

# ifconfig命令不是内建命令,而是一个外部文件
[root@banana ~]# type ifconfig
ifconfig is /usr/sbin/ifconfig

2.执行程序:“.”(点号)

点号用于执行某个脚本甚至脚本没有可执行权限也可以运行。有时候在测试运行某个脚本时可能并不想为此修改脚本权限,这时候就可以使用 “.” 来运行脚本。如果没有运行权限的话,用“./”执行就会有报错但是若在其前面使用点号来执行就不会报错,如下所示:

# 新建HelloWorld.sh,并添加代码
[root@banana ~]# vim HelloWorld.sh
echo "HelloWorld"

# 如果脚本没有可执行权限,则会报权限错误
[root@banana ~]# ./HelloWorld.sh
-bash: ./HelloWorld.sh: Permission denied

# 使用点号执行没有加执行权限的脚本可以正常运行
[root@banana ~]# . ./HelloWorld.sh
HelloWorld!

与点号类似,source命令也可读取并在当前环境中执行脚本,同时还可返回脚本中最后一个命令的返回状态;如果没有返回值则返回0,代表执行成功;如果未找到指定的脚本则返回false

[root@banana ~]# source HelloWorld.sh 
HelloWorld!

3.别名:aliasalias

可用于创建命令的别名,若直接输入该命令且不带任何参数,则列出当前用户使用了别名的命令。现在你应该能理解类似ll这样的命令为什么与ls-l的效果是一样的吧。

[root@banana ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

使用alias可以自定义别名,比如说一般的关机命令是shutdown-h now,写起来比较长,这时可以重新定义一个关机命令,以后就方便多了。使用**alias定义的别名命令也是支持Tab键补全**的,如下所示:

[root@banana ~]# alias myShutdown='shutdown -h now'

注意,这样定义alias只能在当前Shell环境中有效,换句话说,重新登录后这个别名就消失了。为了确保永远生效,可以将该条目写到用户家目录中的.bashrc文件中,如下所示:

[root@banana ~]# cat .bashrc 
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# 自定义关机命令的别名
myShutdown='shutdown -h now'

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

4.删除别名:unalias

该命令用于删除当前Shell环境中的别名。有两种使用方法:

  • 第一种用法:unalias 命令
  • 第二种用法:unalias -a 命令,删除当前Shell环境中所有的别名

同样,这两种方法都是在当前Shell环境中生效的。

# 删除ll别名
[root@banana ~]# unalias ll

# 删除成功,发现.bashrc的ll别名被删除了。
[root@banana ~]# ll
-bash: ll: command not found

# 恢复ll
[root@banana ~]# alias ll='ls -l --color=auto'

5.任务前后台切换:bg、fg、jobs

该命令用于将任务放置后台运行,一般会与Ctrl+z、fg、&符号联合使用。典型的使用场景是运行比较耗时的任务。比如打包某个占用较大空间的目录,若在前台执行,在任务完成前将会一直占用当前的终端,而导致无法执行其他任务,此时就应该将这类任务放置后台。

# 运行打包任务,并使用Ctrl+z组合键暂停前台任务
[root@banana ~]# tar -zcvf Python3.7.5-2.tgz Python-3.7.5
^Z
[1]+  Stopped                 tar -zcf Python3.7.5-2.tgz Python-3.7.5

# 查看任务状态
[root@banana ~]# jobs
[1]+  Stopped                 tar -zcf Python-3.7.5-2.tgz Python-3.7.5

# 继续运行后台任务tar,运行完之后Ctrl+c退出bg
[root@banana ~]# bg 1
^C
[1]+  Done                    tar -zcf Python-3.7.5-2.tgz Python-3.7.5

# 使用fg把后台任务调至前台运行
[root@banana ~]# fg 1

# 如果预知某个任务耗时很久,可以一开始就将命令放入后台运行

[root@banana ~]# tar -zcf Python-3.7.5-2.tgz Python-3.7.5 &
[1] 2215

注意:如果tar命令加了-v参数产生输出,即使后台运行输出也会在打印到前台。此时我们可以使用 > 重定向输出到output文件

[root@banana ~]# tar -vzcf Python-3.7.5-2.tgz Python-3.7.5 > output &
[2] 2223

延伸: 一般我们希望断开远程连接时,任务在后台继续执行,比如Web服务之类的任务。此时我们可以使用nohup 命令 &注意,nohup不是内建命令。

[root@banana ~]# nohup tar -zcf Python-3.7.5-2.tgz Python-3.7.5 &

6.改变目录:cd

改变当前工作目录。如果不加参数,默认会进入当前用户的家目录。

7.声明变量:declare、typeset

这两个命令都是用来声明变量的,作用完全相同。很多语法严谨的语言(比如C语言)对变量的声明都是有严格要求的:变量的使用原则是必须在使用前声明、声明时必须说明变量类型,而Shell脚本中对变量声明的要求并不高,因为Shell弱化了变量的类概念,所以Shell又被称为弱类型编程语言,声明变量时并不需要指明类型。不过,若使用declare命令,可以用-i参数声明整型变量,如下所示:

# 声明整型变量
[root@banana ~]# i_num01=1
# 声明浮点型变量
[root@banana ~]# f_num01=3.14
# 声明字符串变量
[root@banana ~]# str01="HelloWorld"
# 使用declare声明整型变量
[root@banana ~]# declare -i i_num02=1

使用-r声明变量为只读,如下所示:

# -r声明只读变量
[root@banana ~]# declare -r read_only=100
# 试图修改变量值,报错
[root@banana ~]# read_only=200
-bash: read_only: readonly variable

使用-a声明数组变量,如下所示:

[root@banana ~]# declare -a arr='([0]="a" [1]="b" [2]="c")'
[root@banana ~]# echo ${arr[0]}
a
[root@banana ~]# echo ${arr[1]}
b
[root@banana ~]# echo ${arr[2]}
c

使用-F、-f显示脚本中定义的函数和函数体,如下所示:

# 创建脚本fun.sh,内容如下
[root@banana ~]# cat fun.sh 
#!/bin/bash
func_1()
{
	echo "Function 1"
}
func_2()
{
	echo "Function 2"
}
echo "declare -F:"
declare -F

echo "declare -f:"
declare -f

# 运行该脚本输出效果如下
[root@banana ~]# bash fun.sh 
declare -F:
declare -f func_1
declare -f func_2
declare -f:
func_1 () 
{ 
    echo "Function 1"
}
func_2 () 
{ 
    echo "Function 2"
}

8.打印字符:echo

echo用于打印字符,典型用法是使用echo命令并跟上使用双引号括起的内容(即需要打印的内容),该命令会打印出引号中的内容,并在最后默认加上换行符。使用-n参数可以不打印换行符

# 自动换行
[root@banana ~]# echo "HelloWorld"
HelloWorld

# -n参数取消换行
[root@banana ~]# echo -n "HelloWorld"
HelloWorld[root@banana ~]# 

默认情况下,echo命令会隐藏-e参数(禁止解释打印反斜杠转义的字符)。比如“\n”代表新的一行,如果尝试使用echo输出新的一行,在不加参数的情况下只会将“\n”当作普通的字符若要打印转义字符,则需要通过使用-e参数来允许

# echo默认禁止打印反斜杠转义的字符
[root@banana ~]# echo "\n"
\n		# "\n"被当做普通的字符

# 若要打印转义字符,则需要通过使用-e参数来允许
# 输出有两行,第一行是输出的新行,第二行的默认的换行符
[root@banana ~]# echo -e "\n"


[root@banana ~]# 

9.跳出循环:break

从一个循环(for、while、until或者select)中退出。break后可以跟一个数字n,代表跳出n层循环,n必须大于1,如果n比当前循环层数还要大,则跳出所有循环。 下面的脚本演示了使用break和break 2的区别(运行前请将对应的注释符去掉)。


[root@banana ~]# cat break_01.sh 
#!/bin/bash
for I in A B C D
do
	# echo输出I
	echo -n "$I:"
	# J in range(10)
	for J in `seq 10`
		do
			# 如果 J == 5,退出一层循环
			if [ $J -eq 5 ]; then
				break
				# break 2
			fi
			# echo输出J
			echo -n " $J"
		done
	# echo默认会输出"\n"
	echo
done
echo

# 当J值为5时,break的输出结果(外层运行了4次)
[root@banana ~]# bash break_01.sh 
A: 1 2 3 4
B: 1 2 3 4
C: 1 2 3 4
D: 1 2 3 4

# 当J值为5时,break 2的输出结果(外层仅运行了1次)
[root@banana ~]# bash break_01.sh 
A: 1 2 3 4

10.循环控制:continue

停止当前循环,并执行外层循环(for、while、until或者select)的下一次循环。continue后可以跟上一个数字n,代表跳至外部第n层循环。n必须大于1,如果n比当前循环层数还要大,将跳至最外层的循环。 下面的脚本演示了使用continue和continue 2的区别(运行前请将对应的注释符去掉)。

# 创建演示脚本continue
[root@banana ~]# cat continue_01.sh 
#!/bin/bash
# [A,B,C,D]
for I in A B C D
do
	# echo输出I
	echo -n "$I:"
	# J从1,10
	for J in {1..10}
		do
			# 如果J == 5,退出循环
			if [ $J -eq 5 ]; then
				continue
				# continue 2
			fi
			# echo输出J
			echo -n " $J"
		done
	# echo换行
	echo
done
# echo换行
echo

# 判断J值为5时,continue的输出结果
[root@banana ~]# bash continue_01.sh 
A: 1 2 3 4 6 7 8 9 10
B: 1 2 3 4 6 7 8 9 10
C: 1 2 3 4 6 7 8 9 10
D: 1 2 3 4 6 7 8 9 10

# 判断J值为5时,continue 2的输出结果
[root@banana ~]# bash continue_01.sh 
A: 1 2 3 4B: 1 2 3 4C: 1 2 3 4D: 1 2 3 4

11.将所跟的参数作为Shell的输入,并执行产生的命令:eval

# eval用法例一:将字符串解析成命令执行
# 定义cmd为一个字符串,该字符串为"ls -l /etc/passwd"
[root@banana ~]# cmd="ls -l /etc/passwd"

# 使用eval,会将之前的字符串解析为命令并执行
[root@banana ~]# eval $cmd
-rw-r--r-- 1 root root 1171 Jun 10 22:11 /etc/passwd


# eval用法例二:程序运行中根据某个变量确定实际的变量名
[root@banana ~]# name1=john		# 定义变量name1
[root@banana ~]# name2=wang		# 定义变量name2
[root@banana ~]# num=1			# 使用该变量确定真实的变量名name$num
[root@banana ~]# eval echo "$"name$num
john	


# eval用法例三:将某个变量的值当做另一个变量名并给其赋值
[root@banana ~]# name1=john
[root@banana ~]# name2=wang
[root@banana ~]# eval $name1="$name2"
[root@banana ~]# echo $john
wang

12.执行命令来取代当前的Shell:exec

内建命令exec并不启动新的Shell,而是用要被执行的命令替换当前的Shell进程,并且将老进程的环境清理掉,而且exec命令后的其他命令将不再执行。 假设在一个Shell里面执行了exec echo '‘Hello’'命令,在正常地输出一个“Hello”后Shell会退出,因为这个Shell进程已被替换为仅仅执行echo命令的一个进程,执行结束自然也就退出了。如图11-5所示,命令执行完成后,连接状态是一个红色的断开符。
在这里插入图片描述
想要避免出现这种情况,一般将exec命令放到一个Shell脚本里面,由主脚本调用这个脚本,主脚本在调用子脚本执行时,当执行到exec后,该子脚本进程就被替换成相应的exec的命令。注意source命令或者点号,不会为脚本新建Shell,而只是将脚本包含的命令在当前Shell执行。exec典型的用法是与find联合使用,用find找出符合匹配的文件,然后交给exec处理,如下所示:

# 列出系统中所有以.conf结尾的文件
[root@banana ~]# find / -name "*.conf" -exec ls -l {} \;
# 删除系统中所有的.tmp临时文件
[root@banana ~]# find / -name "*.tmp" -exec rm -f {} \;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章