linux shell 个人学习笔记

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

语法

bash支持所有POSIX shell的语法:{% post_link shell/'POSIX-shell学习笔记' %}

下面的是不在POSIX标准里的特性。

条件判断

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

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

重定向

# 等价于 Command > shell.log 2>&1
Command &> shell.log

数组

来源: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[*]}"

例如:

arg_num() {
	echo $#
}
a=(1 "2   3")
# bash 相当于 arg_num 1 2   3
# zsh 相当于 arg_num 1 "2   3"
arg_num ${a[@]}
arg_num ${a[*]}
# 相当于 arg_num 1 "2   3"
arg_num "${a[@]}"
# 相当于 arg_num "1 2   3"
arg_num "${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

长度

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

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

命令行参数

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

# 等价于./test.sh 1 2 3
a=(1 2 3)
./test.sh ${a[@]}
# 从第m个参数开始一直取到末尾
echo ${@:m}
# 从第m个参数开始取n个参数
echo ${@:m:n}

生成序列

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

用户管理

创建普通用户

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

按应用

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不一定存在,可以用这个方式判断:

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

if name1=$(curl -s 'https://api.github.com/users/lambda' | jq -er '.name1'); 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

如果是读取带有特殊字符的域,加上引号即可:

db_size=$(jq -r ".\"db-size\"" < stats.json)

按命令

awk

Linux awk 命令

AWK 条件语句与循环

坑点:如果变量不存在,awk不会报错,而是会把这个变量解析成0:https://stackoverflow.com/questions/49447987/testing-a-non-existent-variable-in-awk

内置函数

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

常用的:

  • length [(String)]

返回 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

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

  • -1: 不输出第一列
  • -2: 不输出第二列
  • -3: 不输出第三列

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

cp

把指定文件夹下面的所有文件和目录复制到另一个文件夹:

cp -a source/. dest

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

cut

       -d, --delimiter=DELIM
              use DELIM instead of TAB for field delimiter

       -f, --fields=LIST
              select  only these fields;  also print any line that contains no delimiter character, unless the -s option is speci‐
              fied

       -s, --only-delimited
              do not print lines not containing delimiters

典型用法:

# 用空格分隔,打印第二个field
echo "hello world" | cut -sd" " -f2

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]

查找规则

  • -name: 根据文件名查找(精确查找)

  • -iname: 不区分大小写

  • !: 逻辑取反,比如\! -name "xxx"就是查找名字跟xxx不匹配的项

查找示例

  • 在当前目录下找到所有名字为input.txt的文件并将其放入回收站
find . -name "input.txt" -exec trash-put {} \;

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

  • 在当前目录下不区分大小写地找以Edition.pdf结尾的文件
find -iname *Edition.pdf
  • 在根目录下查找名字为gsettings的文件或文件夹,但是忽略目录/mnt和/media

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

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:忽略大小写
*:当前目录所有文件。可以换成某个文件名。

  • 查找当前目录下后缀名为.rs的文件中含有splay_safe_rs的文件:
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

  • 正则: -E

里面不支持\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

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

  • -a: 列出所有项。默认会隐藏.开头的项。
  • -l: 列出详细信息。
  • -t: 根据时间倒序排序。

详见: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

{% post_link Other/Language/正则表达式学习笔记 %}

需要注意的是,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,表示全局替换,也就是说在匹配到一个之后不停下来,而是马上继续尝试匹配下一个。

一些例子:

  • 把文件中的CRLF替换成LF

sed 's/\r//g

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

  • 把文件中的LF替换成CRLF

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

posted @ 2024-09-28 14:12  寻找繁星  阅读(1)  评论(0编辑  收藏  举报