Linux 基础操作学习(2):Python 交互
Python OS SYS
OS 库
之前的 Linux 基础教程 中提到了一些可用于目录操作、文件操作的命令,在理解上述知识的基础上我们便可以很快上手 Python os
库的大多数方法。在 Python OS 文件/目录方法 | 菜鸟教程 (runoob.com) 中列出了多达 64 个方法,这里选取几个常用方法介绍。
os.chdir()
作用:改变当前工作目录(change directory),作用类似于 Shell 命令 cd
。
语法格式:os.chdir(path)
参数:
path
:要切换到的路径
返回值:如果允许访问返回 True
,否则返回 False
。
os.getcwd()
作用:返回当前工作目录(get current working directory),作用类似于 Shell 命令 pwd
。
语法格式:os.getcwd()
返回值:返回当前进程的工作目录
os.listdir()
作用:返回指定文件夹包含的文件或文件夹的名字的列表(list directory),作用类似于 Shell 命令 ls
。
语法格式:os.listdir(path)
参数:
path
:需要列出的目录路径
返回值:指定路径 path
下包含的文件或文件夹的名字的列表
os.mkdir()
作用:以指定权限模式创建文件夹(make directory),作用类似于 Shell 命令 mkdir
。
语法格式:os.mkdir(path[,mode])
参数:
path
:要创建的目录路径mode
:八进制整数,为目录设置的权限数字模式。默认为 0777。
os.mkdirs()
作用:以递归方式创建文件夹(make directories),作用类似于 Shell 命令 mkdir -p
。
语法格式:os.mkdirs(path[,mode])
参数:同 os.mkdir()
os.remove()
作用:删除指定路径的文件(remove),作用类似于 Shell 命令 rm
。
语法格式:os.remove(path)
参数:
path
:要删除的文件路径
返回值:无返回值,但如果 path
是一个文件夹,会抛出 OSError
。
os.rmdir()
作用:删除指定路径的空目录(remove directory),作用类似于 Shell 命令 rmdir
。
语法格式:os.rmdir(path)
参数:
path
:要删除的空目录路径
返回值:无返回值,但如果 path
是非空目录,会抛出 OSError
。
os.removedirs()
作用:递归地删除目录,如果子文件夹成功删除继续尝试父文件夹,直到抛出 Error
。作用类似 rmdir -p
语法格式:os.removedirs(path)
参数:
path
:要删除的目录路径
os.open()
作用:以指定打开选项打开一个文件。
语法格式:os.open(file,flags)
参数:
file
:要打开的文件路径flags
:打开模式参数,可以是以下选项,多个则使用|
隔开:os.O_RDONLY
: 以只读的方式打开os.O_WRONLY
: 以只写的方式打开os.O_RDWR
: 以读写的方式打开os.O_NONBLOCK
: 打开时不阻塞os.O_APPEND
: 以追加的方式打开os.O_CREAT
: 创建并打开一个新文件os.O_TRUNC
: 打开一个文件并截断它的长度为零(必须有写权限)os.O_EXCL
: 如果指定的文件存在,返回错误os.O_SHLOCK
: 自动获取共享锁os.O_EXLOCK
: 自动获取独立锁os.O_DIRECT
: 消除或减少缓存效果os.O_FSYNC
: 同步写入os.O_NOFOLLOW
: 不追踪软链接
mode
:权限,默认为 0777,可以用以下选项按位生成:stat.S_IXOTH
: 其他用户有执行权0o001stat.S_IWOTH
: 其他用户有写权限0o002stat.S_IROTH
: 其他用户有读权限0o004stat.S_IRWXO
: 其他用户有全部权限(权限掩码)0o007stat.S_IXGRP
: 组用户有执行权限0o010stat.S_IWGRP
: 组用户有写权限0o020stat.S_IRGRP
: 组用户有读权限0o040stat.S_IRWXG
: 组用户有全部权限(权限掩码)0o070stat.S_IXUSR
: 拥有者具有执行权限0o100stat.S_IWUSR
: 拥有者具有写权限0o200stat.S_IRUSR
: 拥有者具有读权限0o400stat.S_IRWXU
: 拥有者有全部权限(权限掩码)0o700stat.S_ISVTX
: 目录里文件目录只有拥有者才可删除更改0o1000stat.S_ISGID
: 执行此文件其进程有效组为文件所在组0o2000stat.S_ISUID
: 执行此文件其进程有效用户为文件所有者0o4000stat.S_IREAD
: windows下设为只读stat.S_IWRITE
: windows下取消只读
返回值:返回新打开文件的描述符。
os.close()
作用:关闭指定的文件描述符
语法格式:os.close(fd)
参数:
fd
:文件描述符
os.dup2()
作用:将指定文件描述符复制到指定文件描述符
语法格式:os.dup2(fd1,fd2)
参数:
fd1
:要被复制的文件描述符fd2
:复制的文件描述符
os.rename()
作用:重命名文件或目录
语法格式:os.rename(src, dst)
参数:
src
:要修改的目录名dst
:修改后的目录名
os.path
os.path
模块主要用于获取文件的路径,具有很多方法,详见 Python os.path() 模块 | 菜鸟教程 (runoob.com)。
os.walk()
作用:迭代遍历目录,返回指定目录及其子目录下的文件名
语法格式:os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])
参数:
top
:要遍历的目录的地址topdown
:默认为True
,优先遍历top
目录,否则优先遍历子目录onerror
:默认为None
,可填入 callable 对象以供walk()
异常时调用followlinks
:默认为False
;若为True
,则会遍历目录下的快捷方式(软连接)所指向的目录。
返回值:返回一个生成器,是一个三元组 (root, dirs, files)
root
:当前正在遍历的这个文件夹本身的地址dirs
:一个list
,内容是该文件夹中所有目录的名字(不包括子目录)files
:一个list
,内容是该文件夹中所有的文件(不包括子目录)
walk()
与 listdir()
主要的不同点:迭代。即前者会访问子目录
SYS 库
sys
库同样也是 Python 的内置库,下面介绍几个该库常见的方法或成员变量。
sys.argv
获取脚本执行参数列表。一般来说 Python 程序执行参数的第一个参数(sys.argv[0]
)是当前文件名。
sys.path
获取 Python 目录列表。列表中的这些目录供 Python 在其中查找安装的其他模块。在 Python 启动时,sys.path
根据内建规则和 PYTHONPATH
变量进行初始化。这个列表的第一个元素表示当前目录,在交互环境下通常是空字符串。
sys.platform
获取当前运行的平台。如 win32
、linux
。
sys.stdin
Python 的标准输入通道,默认为键盘输入字符。可以将该属性的值改为文件,这样,调用标准输入的方法(如 input()
)就会改为从文件读入。
如:
1 | with open("input.txt") as f: |
sys.stdout
Python 的标准输出通道,默认为屏幕。也可以将该属性的值进行更改,调整输出流。
sys.err
Python 的标准错误输出流,默认为屏幕。
实战
使用 Python 打印命令行参数
- 在
home/datawhale
目录下,昵称文件夹中新建test5.py
- 脚本使用
sys
模块实现打印命令行参数功能
实操:
-
创建文件
1
[I have no name!@i-ym8u2kyp MarioZZJ]$ touch test5.py
-
编辑脚本
1
[I have no name!@i-ym8u2kyp MarioZZJ]$ vim test5.py
脚本内容:
1
2
3import sys
for arg in sys.argv:
print(arg) -
脚本运行与结果
1
2
3
4[I have no name!@i-ym8u2kyp MarioZZJ]$ python test5.py argument1 argument2
test5.py
argument1
argument2
使用 Python 扫描文件目录
- 在
home/datawhale
目录下,昵称文件夹中新建test5.py
- 脚本使用
os
模块实现打印/usr/bin
路径下所有以 m 开头的文件
实操:
-
创建文件(略)
-
编辑脚本
脚本内容:
1
2
3
4
5import os
for filename in os.listdir('/usr/bin'):
# listdir 展示列表包含目录和文件,所以需要条件过滤
if filename[0] == 'm' and os.path.isfile('/usr/bin/'+filename):
print(filename) -
脚本运行与结果
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[I have no name!@i-ym8u2kyp MarioZZJ]$ python test5.py
makedb
make
md5sum
mkdir
mkfifo
mknod
mktemp
mv
mesg
mount
msgattrib
msgcat
msgcmp
msgcomm
msgconv
msgen
msgexec
msgfilter
msgfmt
msggrep
msghack
msginit
msgmerge
msgunfmt
msguniq
miniterm.py
modutil
mcookie
more
man
mountpoint
mkinitrd
machinectl
mapscrn
mailq.postfix
mailq
manpath
mandb
Python 模块化
Python 模块是一个 Python 脚本文件,其中可包含自定义的对象、方法、变量等,供其他 Python 脚本使用。
引入模块
import
语句
Python 脚本文件的后缀是 .py
,通过 import
语句,可以实现对 Python 模块的引入。
如之前提到的 sys
库,当我们 import sys
时,实际上就引入了 Python 标准库中的 sys.py
模块。引入之后就可以使用 sys.*
调用 sys.py
中的方法或变量。
也可以使用 as
子句将引入的模块重命名。import sys as syst
__name__
属性
**当一个模块被另一程序第一次引入时,其主程序将运行。**如果我们想在模块被引入时模块中的某一程序块不被执行,可以使用 __name__
属性来使该程序块仅在该模块自身运行时执行。如:
1 | # Filename: using_name.py |
1 | python using_name.py |
from ... import ...
语句
使用该语句可以从模块中导入指定部分到当前命名空间,如我们仅仅想引入 sys
中的 sys.argv
,可以使用 from sys import argv
,后面可以直接使用 argv
变量(而不是使用 sys.argv
)。
这里也支持引入某模块的所有子对象,即 from [module_name] import *
,但是一般不这么做,因为在很多库中子对象较多,会占用较大命名空间,随后自其他来源创建或引入的命名可能会与之矛盾。
包
包是一种管理 Python 模块命名空间的形式,它是一个分层次的文件目录结构,定义了一个由模块及子包,和子包下的子包等组成的 Python 应用环境。
形如 A.B
的模块中,A
一般为包名,B
为包 A
的子模块。在文件系统中体现为名为 A
的文件夹下的 B.py
。
为了避免非包文件夹被识别为包,只有目录下包含 __init__.py
的文件夹才会被识别为一个包。
1 | /Package_a/ |
实战:在目录下创建包目录,并导入
-
在
home/datawhale
目录下,昵称文件夹中新建affairs
文件夹和test6.py
文件,affairs
文件夹中新建affairs.py
。1
2
3
4
5/home/datawhale/
MarioZZJ/
test6.py
affairs/
affairs.py -
affairs.py
可完成 https://mirror.coggle.club/dataset/affairs.txt 的读取(pandas.read_csv()
) -
test6.py
可以导入affairs.py
代码,并进行命令行解析,输出affairs.txt
的具体第几行内容(行数由命令行参数指定)
实操:
-
新建文件和文件夹
1
2
3
4[I have no name!@i-ym8u2kyp MarioZZJ]$ touch test6.py
[I have no name!@i-ym8u2kyp MarioZZJ]$ mkdir affairs
[I have no name!@i-ym8u2kyp MarioZZJ]$ cd affairs
[I have no name!@i-ym8u2kyp affairs]$ touch affairs.py -
编辑
affairs.py
脚本,内容:1
2
3
4
5
6
7
8import pandas as pd
def parse_line(line_num):
txt = pd.read_csv('https://mirror.coggle.club/dataset/affairs.txt')
if line_num > len(txt):
raise ValueError("Input line number exceeded lenth of file.")
else:
return txt.iloc[line_num]因为
affairs.py
模块在affairs
文件夹中,而test6.py
与affairs
文件夹在同一层级,所以需要通过引入affairs
包的子模块affairs
实现模块引入,而目前affairs
文件夹下没有__init__.py
,该目录不能被识别为包,所以需要创建:1
2
3[I have no name!@i-ym8u2kyp affairs]$ touch __init__.py
[I have no name!@i-ym8u2kyp affairs]$ ls
affairs.py __init__.py -
编辑
test6.py
脚本,内容:1
2
3
4
5
6[I have no name!@i-ym8u2kyp MarioZZJ]$ cat test6.py
from affairs import affairs
import sys
if __name__ == '__main__': # 输入参数为字符串,需转换为整数。因为行数比索引值多 1,须加 1
print(affairs.parse_line(int(sys.argv[1]))+1) -
运行
test6.py
脚本实现文件第 10 行的输出:1
2
3
4
5
6
7
8[I have no name!@i-ym8u2kyp MarioZZJ]$ python3 test6.py 10
rate_marriage 4.0
age 23.0
yrs_married 3.5
children 1.0
religious 3.0
affairs 2.0
Name: 10, dtype: float64
Linux 后台运行、关闭与查看后台任务
&
在命令的最后添加 &
,即可将该命令放到后台执行,此时交互终端可以进行其他操作,而不是默认打印当前命令的输出并等待到进程结束。如:
1 | python3 test.py & |
含 &
的后台运行任务在后台执行,要求当前终端不能关闭。如果终端被关闭(除使用 Ctrl+D
关闭的方法外),执行的这条命令也会随之终止。
nohup
在命令之前添加 nohup
,可将该命令放到后台执行。与 &
有所不同的是,使用 nohup
执行的后台任务在账户退出/终端关闭时仍然继续执行。如:
1 | nohup python3 test.py |
如上,使用 nohup
后会提示忽略输入,输出日志将打印到工作目录下的 nohup.out
文件。此时如果关闭终端,命令仍然会在后台执行。如果不关闭终端,此时的终端是无法交互的。所以如果既要让命令在退出后仍可运行,又想继续和终端交互,可以将 nohup
和 &
一起使用,即:nohup [command] &
。
如果想指定输出文件的位置(而不是 nohup.out
),可以利用 Linux 的输出重定向符号 >
:nohup [command] > output.log &
Ctrl+Z
在命令执行过程中,按下 Ctrl+Z
可以挂起进程,此时该进程处于暂停状态,即不继续执行进程且稍后可以恢复。
jobs
使用 jobs
命令可以显示当前控制台创建的任务。 jobs 的状态可以是 running
, stopped
, Terminated
。如使用 jobs -l
可以查看所有后台运行任务的 pid
,这样可以根据 pid
操作对应进程。
1 | [I have no name!@i-ym8u2kyp MarioZZJ]$ jobs -l |
([ ]
内为进程 job 号,如这里为 1;后面为 pid
,如这里为 18860)
bg
使用 bg
命令可以将后台暂停的命令变为在后台继续执行。(back go)
语法格式: bg <jobid>
该命令可以和 Ctrl+Z
、jobs
较好配合使用。一般常用的做法如:
1 | [I have no name!@i-ym8u2kyp MarioZZJ]$ nohup python3 test_temp.py # 单独 nohup 执行命令 |
fg
使用 fg
命令可以将后台命令变为在前台执行。(fore go)
语法格式:fg [jobid]
kill
使用 kill
命令可以结束(kill)进程。
语法格式:
kill %<jobid>
kill <pid>
tmux
tmux
是一个终端复用软件,使用 tmux
可以实现在一个终端登录远程主机,并在该终端窗口中运行多个终端对话,也可按需使终端会话运行于后台或是按需接入、断开会话。下面列出 tmux 的主要操作,更多详细操作可参见 Tmux终端复用详解 (cnblogs.com) 。
安装
以我所使用的 CentOS 系统为例,需要先安装 tmux
才可使用:
1 | yum install -y tmux |
创建会话
使用 tmux
即可打开软件(单独使用 tmux
命令会创建一个会话,以数字命名),可以加上命令 new -s
对创建的会话进行命名:
1 | tmux new -s name |
列出创建的所有会话
添加命令 ls
即可列出创建的所有会话
1 | [I have no name!@i-ym8u2kyp ~]$ tmux ls |
登录一个会话
添加命令 attach
(或简写为 a
)并附加参数 -t <会话名>
即可使用 tmux 登录一个已知会话。
退出会话
- 依次按
Ctrl+b
、d
即可退出会话,但不关闭该会话。 - 按
Ctrl+d
退出并直接关闭该会话 tmux kill-session -t <会话名>
可以销毁指定会话。
快捷键
进入 tmux 面板后,按 Ctrl+b
再按其他按键,即可进行一系列快捷操作:
Ctrl+b | 按键 | 说明 |
---|---|---|
ctrl +b |
? |
显示快捷键帮助 |
ctrl +b |
[space] |
采用下一个内置布局,这个很有意思,在多屏时,用这个就会将多有屏幕竖着展示 |
ctrl +b |
! |
把当前窗口变为新窗口 |
ctrl +b |
" |
模向分隔窗口 |
ctrl +b |
% |
纵向分隔窗口 |
ctrl +b |
q |
显示分隔窗口的编号 |
ctrl +b |
o |
跳到下一个分隔窗口。多屏之间的切换 |
ctrl +b |
↑ /↓ |
上一个及下一个分隔窗口 |
ctrl +b |
C +↑ /↓ /← /→ |
调整分隔窗口大小 |
ctrl +b |
& |
确认后退出当前 tmux |
ctrl +b |
[ |
复制模式,即将当前屏幕移到上一个的位置上,其他所有窗口都向前移动一个。 |
ctrl +b |
c |
创建新窗口 |
ctrl +b |
n |
选择下一个窗口 |
ctrl +b |
l |
最后使用的窗口 |
ctrl +b |
p |
选择前一个窗口 |
ctrl +b |
w |
以菜单方式显示及选择窗口 |
ctrl +b |
s |
以菜单方式显示和选择会话。这个常用到,可以选择进入哪个 tmux |
ctrl +b |
t |
显示时钟。然后按 enter 键后就会恢复到 shell 终端状态 |
ctrl +b |
d |
脱离当前会话;这样可以暂时返回 Shell 界面,输入 tmux attach 能够重新进入之前的会话 |
实战:在 Linux 系统后台运行应用程序,并打印日志
- 在
home/datawhale
目录下,昵称文件夹中新建sleep.py
文件,该脚本能一直运行并每隔 10 秒输出当前时间 - 使用适当的命令能使该程序后台运行,并将输出结果写入 txt 文件。
实操:
-
创建脚本,内容如下:
1
2
3
4
5import time
while(True):
print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
time.sleep(10) -
利用
nohup
、&
命令和输出重定向实现后台运行,并查看日志1
2
3
4
5
6
7[I have no name!@i-ym8u2kyp MarioZZJ]$ nohup python3 sleep.py > output.log & # 后台运行
[1] 15563
nohup: ignoring input and redirecting stderr to stdout
[I have no name!@i-ym8u2kyp MarioZZJ]$ jobs -l # 查看 job,刚才的任务正在运行
[1]+ 15563 Running nohup python3 sleep.py > output.log &
[I have no name!@i-ym8u2kyp MarioZZJ]$ cat output.log # 查看输出内容,结果为空!!
[I have no name!@i-ym8u2kyp MarioZZJ]$出现问题:使用
cat
查看输出的日志内容,为空!查询资料后发现原因:Python 的两个输出流
stdout
和stderr
都是默认指向屏幕,我们的命令将其输出重定向到文件,但是二者机制不同。stderr
无缓存,程序每往stderr
输出时都会立刻输出到指定的目标,而stdout
有缓存,只有遇到需要清空缓存的情况才会向目标输出(如输出为屏幕时的换行,程序结束时的缓存清空等),为使运行过程中输出内容可以实时输出至日志,可以为python
命令附加-u
参数以取消缓存。重新操作:
1
2
3
4
5
6
7
8
9[I have no name!@i-ym8u2kyp MarioZZJ]$ nohup python3 -u sleep.py > outlog.txt &
[1] 18442
nohup: ignoring input and redirecting stderr to stdout
[I have no name!@i-ym8u2kyp MarioZZJ]$ jobs -l
[1]+ 18442 Running nohup python3 -u sleep.py > outlog.txt &
[I have no name!@i-ym8u2kyp MarioZZJ]$ cat outlog.txt
2021-12-21 15:29:44
2021-12-21 15:29:54
[I have no name!@i-ym8u2kyp MarioZZJ]$
- 感谢您的赞赏