linux shell 个人学习笔记

阅读量: searchstar 2020-02-05 18:10:23
Categories: Tags:

安全重启:
按住alt+<PrtSc>,然后依次按下reisub即可安全重启。

语法

条件判断

man bash,然后搜索CONDITIONAL EXPRESSIONS,可以看到完整的列表。

if elif else

参考:https://blog.csdn.net/u014783674/article/details/24474001

#!/bin/bash
if [ condition1 ]; then
	# Do something
elif [ condition2 ]; then
	# Do something
else
	# Do something
fi

判断某环境变量是否存在

参考:https://blog.csdn.net/blade2001/article/details/7243143?utm_source=blogxgwz3

上面的文章好像写反了

例子:判断环境变量DISPLAY是否存在(若不存在说明没有提供显示设备)

if [ $DISPLAY ]; then
	# DISPLAY存在
else
	# DISPLAY不存在
fi

或者

if [ ! $DISPLAY ]; then

表示如果$DISPLAY不存在

字符串

功能 例子
为空 [ -z "$1" ] 或者 [ ! "$1" ]
非空 [ -n "$1" ] 或者 [ "$1" ]
相等 [ "$1" == "$2" ]
不相等 [ "$1" != "$2" ]

所以如果判断目录是否非空,可以这样:if [ "$(ls -A xxx)" ]

参考:https://www.cyberciti.biz/faq/linux-unix-shell-check-if-directory-empty/

整数的大小判断

参考:
https://blog.csdn.net/shang_feng_wei/article/details/90378017
https://www.jb51.net/article/56553.htm
https://blog.csdn.net/HappyRocking/article/details/90609554#1_70

代码 含义 例子
-eq = [ $1 -eq 2 ]
-ne != [ $1 -ne 2 ]
-le <= [ $1 -le 2 ]
-lt < [ $1 -lt 2 ]
-ge >= [ $1 -ge 2 ]
-gt > [ $1 -gt 2 ]
-a && [ $1 -gt 0 -a $1 -lt 10 ]
-o || [ $1 -lt 0 -o $1 -gt 10 ]

其中-eq-ne可以分别用=!=替换。

如果想像C语言那样进行条件判断,可以使用[[]]
例如下面这两句都表示如果参数的个数等于0或者大于2

if [[ $# = 0 || $# > 2 ]]; then
if [ $# = 0 -o $# -gt 2 ]; then

浮点数的大小判断

if awk "BEGIN {exit !(1.234 >= .233)}"; then
    echo "yes"
fi

来源:https://stackoverflow.com/a/45591665/13688160

判断文件类型

来源:https://jingyan.baidu.com/article/95c9d20d5ac536ec4e7561ad.html

#!/bin/bash
if [ -z $1 ]; then      #如果没有输入参数,也就是第一个参数的字符串长度为0
    :                          #空语句
else
	if [ -e $1 ]; then       #如果文件存在的话
		if [ -f $1 ]; then   #如果文件是个普通文件?
			echo $1" is a text file."
		elif [ -d $1 ]; then #如果文件是个目录文件?
			echo $1" is a directory."
		elif [ -c $1 ]; then #如果文件是个字符设备?
			echo $1" is a char device."
		elif [ -b $1 ]; then #如果文件是个块设备?
			echo $1" is a block device."
		else #否则
			echo $1" is unknow file."
	fi
fi

另外,-s表示文件存在且不为空。来源:https://stackoverflow.com/questions/9964823/how-to-check-if-a-file-is-empty-in-bash

判断文件权限

代码 含义
-r 存在且可读
-w 存在且可写
-x 存在且可执行

参考:https://stackoverflow.com/questions/10319652/check-if-a-file-is-executable

函数

参考:https://www.runoob.com/linux/linux-shell-func.html

定义

function FunctionName {
	do_some_thing_here
	return Interger
}

其中function可以省略,也可以不return。
参数用法与脚本类似。($#表个数,$1, $9, ${10}表具体参数)

使用

FunctionName par1 par2 par3

循环

while

参考:https://wiki.jikexueyuan.com/project/shell-tutorial/shell-while-loop.html

while Command
do
   Statement(s) to be executed if Command is true
done

或者

while [ Condition ]; do
	Statement(s) to be executed if Condition is true
done

也可以对命令返回值取反,比如

while ! Command; do
	Statement(s) to be executed if Command is false
done

for

参考:https://blog.csdn.net/astraylinux/article/details/7016212

for ((i=0; i<10; ++i))  
do  
    echo $i  
done  

注意是双括号。
还有其他用法。看参考链接

正则表达式

if [[ 字符串 =~ 模式 ]]; then
	echo 字符串中含有模式
fi

比如最简单的:

if [[ 2333test233222 =~ test233 ]]; then
	echo yes;
fi

会打印出yes

如果要判断是否不包含:

if ! [[ 2333test233222 =~ test233 ]]; then
	echo yes;
fi

或操作:

if [[ 2333test233222 =~ abc || 2333test233222 =~ test233 ]]; then
	echo yes;
fi
# yes

与操作:

if [[ 2333test233222 =~ abc && 2333test233222 =~ test233 ]]; then
	echo yes;
fi

重定向

# 将`stdout`重定向到`stdout.txt`
Command > stdout.txt
# 将`stderr`重定向到`stderr.txt`
Command 2> stderr.txt
# 将stderr重定向到stdout
Command 2>&1
# 将stderr和stdout都重定向到一个文件
# 参考:<https://blog.csdn.net/u011630575/article/details/52151995>
Command > shell.log 2>&1
Command &> shell.log
# 将`stdin`重定向到`stdin.txt`
Command < stdin.txt
# 将Command1的stdout输入到Command2的stdin
Command1 | Command2 # 例如 echo 'whoami' | bash,可以让bash执行whoami。

将多行字面量作为stdin

Command <<标记
第一行
第二行
...
标记

例如:

bash <<EOF
whoami
echo 2333
EOF

数组

来源:https://www.yiibai.com/bash/bash-array.html

定义

ARRAY_NAME=(element_1st element_2nd element_Nth)

访问某个下标的元素

下标从0开始。

echo ${ARRAY_NAME[2]}

访问所有元素

# 经实测,bash是每个元素一个不带引号的结果,zsh是每个元素一个带引号的结果
echo ${ARRAY_NAME[@]}
echo ${ARRAY_NAME[*]}
# 每个元素一个带引号的结果
echo "${ARRAY_NAME[@]}"
# 所有元素组成一个结果
echo "${ARRAY_NAME[*]}"

例如:

a=(1 "2   3")
# bash 相当于 echo 1 2   3
# zsh 相当于 echo 1 "2   3"
echo ${a[@]}
echo ${a[*]}
# 相当于 echo 1 "2   3"
echo "${a[@]}"
# 相当于 echo "1 2   3"
echo "${a[*]}"

访问slice

# 从第m个开始一直到末尾
${ARRAY_NAME[@]:m}
# 从第m个开始取n个。下标从0开始。
${ARRAY_NAME[@]:m:n}

保存为新的数组:

SLICED_ARRAY=(${ARRAY_NAME[@]:m:n})

参考:https://stackoverflow.com/questions/1335815/how-to-slice-an-array-in-bash

命令行参数

命令行参数也是数组,用法跟上面的差不多:

# 访问某参数
echo $2
# 所有参数
echo $@
echo $*
# 从第m个参数开始一直取到末尾
echo ${@:m}
# 从第m个参数开始取n个参数
echo ${@:m:n}
# 参数个数(不含$0)
echo $#

当数组被用于命令行参数时,会被展开成一个个参数:

# 等价于./test.sh 1 2 3
a=(1 2 3)
./test.sh ${a[@]}

生成序列

a=($(seq 1 4))
echo "${a[@]}"
1 2 3 4

参考:https://stackoverflow.com/questions/39267836/create-an-array-with-a-sequence-of-numbers-in-bash

新增元素

a=(1 2 3)
a+=(4 5)
echo "${a[@]}"
1 2 3 4 5

进程

获取当前subshell的PID:

pid=$(exec sh -c 'echo "$PPID"')

来源:https://unix.stackexchange.com/a/484464

信号

trap 信号处理命令 信号名

例如:

Linux杀死所有子进程
# 在脚本退出前杀死所有子进程
trap "pkill -P $$" EXIT

用户管理

创建普通用户

adduser 用户名

但是有些发行版没有adduser命令,就只能用useradd命令创建用户了:

# -m: 创建家目录
useradd -m 用户名
# 设置密码
passwd 用户名

创建系统用户

# -r, --system: 创建系统用户,UID小于1000,无密码,无家目录,无法登录。
useradd --system 用户名

来源:https://superuser.com/a/515909/1677998

以另一用户的身份执行命令

参考:https://www.cnblogs.com/bigben0123/archive/2013/05/07/3064843.html

sudo -u UserName Command

判断用户是否存在

if id "$1" &>/dev/null; then
    echo 'user found'
else
    echo 'user not found'
fi

来源:https://stackoverflow.com/questions/14810684/check-whether-a-user-exists

创建组

sudo groupadd GroupName

向组中加入用户

参考:https://blog.csdn.net/u013078295/article/details/52173311

sudo usermod -aG GroupName UserName

查看group里的用户

参考:https://blog.csdn.net/withiter/article/details/8132525里的评论

grep GroupName /etc/group

set

bash可以用set来设置一些模式。

子命令返回值不为0时退出

set -e

但是要注意的是,对于用管道连接起来的几个命令,最终的exit code似乎是管道里的最后一个命令。例如对于command A | command B,如果command A出错返回非0,但是command B正常退出,那么这个组合命令的exit code会被设置成0,这样set -e就不会生效。

如果要让被管道组合起来命令中任何一个命令返回非0都会退出,则需要加上set -o pipefail,其效果是将exit code赋值为被管道组合起来的命令中最后一个返回非0值的命令。

来源:Get exit status of process that's piped to another

按应用

crontab

启动

service cron start

按功能

查看磁盘占用情况

df -h

以默认应用打开文件

xdg-open FileName

按照十六进制查看文件

hexdump -C FileName > hex.out

查看命令执行时间

time 命令

查看8进制文件权限

参考:http://novell.me/Linux/201410/stat-get-file-permission-with-octal-numb.html

stat -c %a FileName

监视某命令的执行结果

watch -n Interval Command

Interval: 执行间隔,以秒为单位

获取精确到纳秒的当前时间

参考:https://blog.csdn.net/gengshenghong/article/details/7583580

date +%Y%m%d%X%N

时间戳

date +%s%N

时间戳转时间字符串

date --date='@2147483647'

查看端口占用情况

参考:https://jingyan.baidu.com/article/656db9183861cde381249c87.html

lsof -i:8236

查看8236端口的占用情况。无输出表示没有被占用。

查看发行版信息

参考:https://blog.csdn.net/sty945/article/details/96475882

lsb_release -a

我的输出:

No LSB modules are available.
Distributor ID:	Deepin
Description:	Deepin 15.11
Release:	15.11
Codename:	stable

清空命令历史记录

参考:https://zhidao.baidu.com/question/1495253179240949419.html

history -c

创建临时文件

mktemp

便会在/tmp下创建一个文件并把文件名输出到stdout。
示例:

echo Please input:
read -s input
tmp=$(mktemp)
echo $input > $tmp
cat $tmp
rm $tmp

转义

# hello\\world
printf "%q" "hello\world"
# var='hello\\world'
printf -v var "%q\n" "hello\world"

来源:https://stackoverflow.com/a/2856010/13688160

使用ImageMagick将多个jpg转换为A4大小的PDF

转自:https://blog.csdn.net/lpwmm/article/details/83503736

convert a.png b.png -compress jpeg -resize 1240x1753 \
				  -extent 1240x1753 -gravity center \
				  -units PixelsPerInch -density 150x150 multipage.pdf

如果不想限定高度,可以

convert a.png b.png -compress jpeg -resize 1240 \
				  -extent 1240 -gravity center \
				  -units PixelsPerInch -density 150x150 multipage.pdf

生成随机数

echo $RANDOM

生成长度为n字节的16进制随机数(最终生成的16进制字符串的长度是2n):

openssl rand -hex n

来源:Linux Shell产生16进制随机数

提取文件后缀名

filename=test.tar.gz
# gz
echo ${filename##*.}
# tar.gz
echo ${filename#*.}

来源:https://stackoverflow.com/questions/965053/extract-filename-and-extension-in-bash

带单位容量转字节数

pip3 install humanfriendly
# 2000
humanfriendly --parse-size="2 KB"
# 2048
humanfriendly --parse-size="2 KiB"

来源:https://stackoverflow.com/a/46373468

读取JSON

jq

# Debian
sudo apt install jq
# ArchLinux
sudo pacman -S jq
curl -s 'https://api.github.com/users/lambda' | jq -r '.name'
Brian Campbell

如果field不一定存在,可以用这个方式判断:

name=$(curl -s 'https://api.github.com/users/lambda' | jq -er '.name')
if [ $? -eq 0 ]; then
	echo $name
else
	echo name does not exist
fi

name1=$(curl -s 'https://api.github.com/users/lambda' | jq -er '.name1')
if [ $? -eq 0 ]; then
	echo $name1
else
	echo name1 does not exist
fi
Brian Campbell
name1 does not exist
○   -e / --exit-status:

	Sets  the  exit status of jq to 0 if the last output values was neither false nor null, 1 if the last output value was either false or null, or 4 if no valid result was ever produced.

参考:https://stackoverflow.com/a/53135202/13688160

按命令

awk

Linux awk 命令

AWK 条件语句与循环

内置函数

完整列表:https://www.runoob.com/w3cnote/awk-built-in-functions.html

常用的:

返回 String 参数指定的字符串的长度(字符形式)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量)。

求和

seq 1 10 | awk '{s+=$1} END {print s}'

来源:https://stackoverflow.com/questions/450799/shell-command-to-sum-integers-one-per-line

打印到stderr

print "Serious error detected!" > "/dev/stderr"

官方文档:https://www.gnu.org/software/gawk/manual/html_node/Special-FD.html

exit

exit [return code]

next

立即停止处理当前record,开始处理下一个record。

column

cat table | column -t可以输出一个漂亮的表格。

来源:https://stackoverflow.com/a/28755377/13688160

comm

求两个有序文件中的相同行和不同行。第一列是只在第一个文件中的行,第二列是只在第二个文件中的行,第三列是两个文件都存在的行。常用命令行选项:

参考:https://unix.stackexchange.com/questions/28865/list-the-difference-and-overlap-between-two-plain-data-set

diff

忽略换行符的区别:--strip-trailing-cr

来源:https://stackoverflow.com/questions/40974170/how-can-i-ignore-line-endings-when-comparing-files

dpkg

显示当前已经安装的软件

dpkg --list

查看文件由哪个包提供

$ dpkg -S /bin/ls
coreutils: /bin/ls

来源:https://askubuntu.com/a/482

du

-d数字: 目录层数。0表示当前目录,1表示当前目录下的所有文件和子目录,以此类推。

--all: 显示文件大小。默认只显示目录大小。

du -h

-h--human-readable的缩写。

du -sh

-s--summarize的缩写。

du -hd 1 --all 目录 | sort -h

来源:https://serverfault.com/questions/62411/how-can-i-sort-du-h-output-by-size

参考:https://jingyan.baidu.com/article/ca2d939d7867e0eb6c31ce80.html

find

find [目录] [查找规则] [查找完后执行的action]

查找规则

查找示例

find . -name "input.txt" -exec trash-put {} \;

其中{}替代查找到的文件,”;”是-exec的结束符

find -iname *Edition.pdf

这些都不对,不知道为什么

sudo find / -name “gsettings” ! -path “/mnt/*” ! -path “/media/*”
sudo find / -path /media -path /mnt -prune -o -name gsettings
sudo find . -name media -name mnt -prune -o -name gsettings
sudo find . -path ./media -path ./mnt -prune -o -name gsettings
sudo find . -name b ! -path “./a/*”

正则

查找规则部分:-regex '正则表达式'

正则表达式匹配的是完整路径。

例子:

find . -regex '.*/latency-[0-9]*'
./latency-2
./latency-4
./latency-3
./latency-5
./latency-1
./latency-6
./latency-7
./latency-0

来源:https://stackoverflow.com/questions/6844785/how-to-use-regex-with-find-command

grep

       -v, --invert-match
              Invert the sense of matching, to select non-matching lines.
       -m NUM, --max-count=NUM
              Stop reading a file after NUM matching lines.  If  the  input  is  standard
              input  from a regular file, and NUM matching lines are output, grep ensures
              that the standard input is positioned to just after the last matching  line
              before exiting, regardless of the presence of trailing context lines.  This
              enables a calling process to resume a search.  When grep  stops  after  NUM
              matching  lines,  it  outputs  any  trailing context lines.  When the -c or
              --count option is also used, grep does not output a count greater than NUM.
              When  the  -v  or  --invert-match  option  is  also  used, grep stops after
              outputting NUM non-matching lines.
grep -rn string *

-r:递归查找
-n:显示行号
-i:忽略大小写
*:当前目录所有文件。可以换成某个文件名。

grep -rn splay_safe_rs --include \*.rs

来源:https://stackoverflow.com/questions/12516937/how-can-i-grep-recursively-but-only-in-files-with-certain-extensions

--exclude, --exclude-dir: https://www.warp.dev/terminus/grep-exclude

里面不支持\d之类的,只支持[0-9]

ip

查看本机ip地址

ip addr

join

https://www.geeksforgeeks.org/join-command-linux/

less

最基础用法:

less 文件路径

显示行号:

less -N 文件路径

也可以在less里面按- N Enter即可显示/隐藏行号。

跳转到指定行:在less里面输入自己要跳转的行号,然后按g

来源:Linux之Less命令跳转到特定的行号

locate

locate name

查找文件(文件夹)

ls

列出目录中的文件和文件夹。常用命令行选项:

详见:https://blog.csdn.net/nb1253587023/article/details/127188039

pidof 进程名

返回某进程名对应的pid
例子:
杀掉所有名字为ssh-agent的进程

kill $(pidof ssh-agent)

rm

-d: 当目录为空时才删除目录。

sed

从stdin读入,将修改后的结果写入到stdout:

sed '命令'

其中命令形如s/源pattern/目的pattern/g(全局替换)

从文件读入,将修改后的结果写入到stdout:

sed '命令' FileName

基础知识

sed模式空间(pattern space)和保持空间(hold space)

https://stackoverflow.com/questions/12833714/the-concept-of-hold-space-and-pattern-space-in-sed

sed读取一行时,会先将其暂存到模式空间。处理完一行之后就会把模式空间中的内容打印到标准输出,然后自动清空缓存。

保持空间是sed中的另外一个缓冲区,此缓冲区正如其名,不会自动清空,但也不会主动把此缓冲区中的内容打印到标准输出中。

d: 删除模式空间的内容,开始下一个循环

g: 复制保持空间的内容到模式空间

s/regexp/replacement/: 在模式空间中如果匹配到了正则表达式regexp,就将其替换为replacement

正则表达式学习笔记

需要注意的是,sed的正则表达式中,如果用到了(, ), |,需要在前面放一个\将它们转义,例如sed '/\(patternx\|patterny\)/p'。来源:https://stackoverflow.com/questions/14813145/boolean-or-in-sed-regex

全局替换

sed 's/regexp/replacement/g'

其中s是替换命令,表示在模式空间尝试匹配正则表达式regexp,找到了就将其替换为replacement

这里的g不是命令,而是隶属于s命令的一个flag,表示全局替换,也就是说在匹配到一个之后不停下来,而是马上继续尝试匹配下一个。

一些例子:

sed 's/\r//g

\r就是CR,将其替换成空就相当于把它删了。

sed 's/$/\r/g

$的意思是每行的末尾。在每行的末尾把空字符串替换成\r(CR),也就是插入\r(CR)。在linux中换行是LF,所以相当于在LF前面插入一个CR,变成CRLF。

sed 's/.* //g

正则表达式里,点.几乎可以匹配任何字符,所以.*会尽量匹配尽量长的字符串。/.* /表示最长的以空格结尾的字符串。目的pattern为空,这样就相当于把每行的最长的以空格结尾的字符串删掉。所以每行只留下了最后一个单词了。

参考:https://blog.csdn.net/lwlfox/article/details/85065026

sed 's/\b\S*\b/test&/g

\b: 单词边界
&: 前面匹配的字符串

有点像scanfprintf的组合:

https://blog.csdn.net/scl323/article/details/84098366

删除匹配行

sed '/regexp/d'

如果模式空间有可以匹配正则表达式regexp的子串,那么就将模式空间删除,然后继续读取下一行到模式空间。

常用选项

-i: 直接修改文件(默认是输出编辑后的结果到stdout)。

--follow-symlinks: -i会破坏符号链接和硬链接,加上这个选项之后可以保护软链接不被破坏,但是不保护硬链接。参考:https://www.cnblogs.com/cherryhaha1234/p/10848024.html

-c: 保护符号链接和硬链接(但是我的sed没有这个选项)。

-n: sed默认会将文件的每行打印出来,然后对匹配的内容进行相应的操作。-n表示不把文件的每行都打印出来,只对匹配的内容做相应的操作。

匹配指定行:sed -n 起始行号[,终止行号]动作 file,动作一般是p,即打印(Print)。

例子:

打印第2行:sed -n '2p' file

打印第2行到第4行:sed -n '2,4p' file

参考:https://www.commandlinefu.com/commands/view/3802/to-print-a-specific-line-from-a-file

sort

-k列号: 按这一列排序。列号从1开始。

-r: 逆序

-n: --numeric-sort。按照数字排序。默认是按照字符串排序。

-o 文件: 输出到文件。默认是输出到stdout的。

排序

参考:https://stackoverflow.com/a/17048248

去重

参考网站:https://www.cnblogs.com/rwxwsblog/p/4564216.html

例如txt中有

jason
jason
jason
fffff
jason

执行以下命令

sort -u txt

输出

fffff
jason

输出到文件

sort -u txt -o txt1

top

-H: 显示单个线程。https://serverfault.com/questions/38195/getting-a-per-thread-cpu-stats

其他

{ post_link shell/'zsh使用笔记' }

linux中怎么用shell显示文件某一行或几行内容

linux shell 将多行文件转换为一行

[[[的区别:https://stackoverflow.com/questions/3427872/whats-the-difference-between-and-in-bash