Python数据处理
¶

10. UNIX/LINUX命令行
¶

主讲人:丁平尖

Linux的发展历史¶

  • 1969, Bell Laboratory, UNIX
  • 1984, Richard Stallman, GNU (GNU is Not Unix) and GPL (General Public License)
  • 1987, Andrew S. Tanenbaum, MINIX
  • 1991, Linus Torvalds, Linux内核, based on MINIX
  • 1994.3, Linux 1.0 released
  • 1995, Bob Young, RedHat
  • 2022.8.1, Linux Kernel 5.19

Linux不同的发行版本¶

image.png

最受欢迎Linux桌面操作系统¶

  • 根据阿里云镜像下载统计数据:
      1. CentOS:CentOS是Linux发行版之一,它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代码所编译而成。
      1. Ubuntu:一个完整的桌面 Linux 操作系统,免费提供比其他发行版更大的社区支持。
      1. Kali Linux
      1. Arch Linux
      1. Debian
      1. Deepin (深度)
      1. Linux Kylin (优麒麟)
      1. Fedora
      1. Manjaro
      1. OpenSUSE

Linux系统的特点¶

  • 命令行操作方式
  • 自由软件
  • 安全性高
  • 多任务多用户
  • 性能强大
  • 网络支持好
  • 扩展性好

Linux系统安装¶

  • 完整安装
    • 性能好;但需要重新分区,安装复杂,使用不便。
  • 虚拟机安装
    • VMware,Virtual Box,Virtual PC
    • 不影响原系统;但性能较差,使用不太方便。
  • Windows 10/11 内置Linux子系统(WSL)
    • 安装方便,不需要重新分区
    • 使用方便,可共享宿主系统的文件和网络

Remote Development¶

  • VS Code: Remote Development
    • https://code.visualstudio.com/docs/remote/remote-overview

image.png

Remote Development¶

  • Pycharm: GateWay
    • https://www.jetbrains.com/help/pycharm/remote-development-starting-page.html#run_in_wsl_ij

image.png

Shell¶

  • Shell是用户与操作系统内核之间沟通的桥梁,也是Linux的脚本语言的解释器。
    • 流行的shell:bash(Bourne Again Shell)、csh(C Shell)、ksh(Korn Shell)
  • Redirect:将一个程序的输出作为另一个程序的输入。

image.png

  • stdin、stdout、stderr:三个特殊的“文件句柄”
    • 用于从shell读取输入(stdin)和向shell写入输出(stderr用于错误消息,stdout用于其他信息)。

命令行提示符的组成部分¶

image-2.png

  • 用户名@主机名:当前目录 提示符/分隔符

连接到其他机器:ssh¶

  • ssh(Secure Shell)网络协议允许安全通信机器
  • 允许远程访问资源,例如服务器或计算集群
  • ssh user@machine
  • 服务器和客服端分别安装OpenSSH Server和OpenSSH Client

subprocess模块¶

  • subprocess 模块是 Python 中用于生成和管理子进程的模块,适合执行系统命令和与子进程进行交互.
  • https://docs.python.org/3/library/subprocess.html
  • subprocess.run:用于执行一个命令并等待其完成。适用于执行简单命令和一次性任务。
    • 运行args描述的命令。等待命令完成,然后返回一个CompletedProcess对象。
    • subprocess.run(args, *, stdin = None, input = None, stdout = None, stderr = None, capture_output = False, shell = False, cwd = None, timeout = None, check = False, encoding = None, errors = None, text = None, env = None, universal_newlines = None, ** other_popen_kwargs)
  • CompletedProcess对象的属性
    • args: 用于启动进程的参数。可以是列表或字符串。
    • returncode: 子进程的退出状态。通常,退出状态 0 表示它已成功运行。
    • stdout: 从子进程捕获的标准输出
    • stderr: 从子进程捕获 stderr。如果未捕获 stderr,则为字节序列或字符串
    • check_returncode(): 如果returncode非零,则引发CalledProcessError。
In [1]:
import subprocess
x = subprocess.run("pwd", shell=True)
/mnt/c/Users/ASUS/Desktop/PPT
In [2]:
print(x.stdout)
x = subprocess.run("pwd", shell=True, capture_output=True)
print(x.stdout)
print(x.returncode)
None
b'/mnt/c/Users/ASUS/Desktop/PPT\n'
0

Jupyter Notebook中运行shell命令¶

  • 使用!前缀
  • 使用%前缀
  • 使用%%bash
    • 在一个单元格中执行多个shell命令
In [5]:
!pwd
/mnt/c/Users/ASUS/Desktop/PPT
In [6]:
%pwd
Out[6]:
'/mnt/c/Users/ASUS/Desktop/PPT'
In [8]:
%%bash
pwd
echo $SHELL
/mnt/c/Users/ASUS/Desktop/PPT
/bin/bash

基本命令用于导航¶

  • pwd:打印/当前工作目录。打印你当前所在的目录。
  • ls:列出当前目录的内容。
  • cd dirname:将工作目录更改为dirname。
  • 一些特殊的目录符号:
    • ~:你的家目录。
      • cd ~将带你回到你的家目录。
    • ..:当前目录以上的目录。
      • 如果你在/mnt/c/Users/ASUS/Desktop/PPT,那么cd ..将带你到/mnt/c/Users/ASUS/Desktop。
In [3]:
subprocess.run("pwd;", shell=True)
/mnt/c/Users/ASUS/Desktop/PPT
Out[3]:
CompletedProcess(args='pwd;', returncode=0)
In [74]:
subprocess.run("cd lecture02_files; pwd;", shell=True)
/mnt/c/Users/ASUS/Desktop/PPT/lecture02_files
Out[74]:
CompletedProcess(args='cd lecture02_files; pwd;', returncode=0)
In [75]:
subprocess.run("cd lecture02_files; ls;", shell=True)
figure-html
libs
Out[75]:
CompletedProcess(args='cd lecture02_files; ls;', returncode=0)

基本命令:echo¶

  • echo string:将字符串打印到shell。
In [76]:
subprocess.run("echo 'hello world!'", shell=True)
hello world!
Out[76]:
CompletedProcess(args="echo 'hello world!'", returncode=0)

使用>重定向¶

  • 如果我想将输出发送到其他地方怎么办?
  • 重定向告诉shell将程序的输出从“大于”侧发送到“小于”侧的文件。这在右侧创建文件,并覆盖已存在的旧文件!
In [9]:
subprocess.run("echo 'hello world!' > myfile.txt", shell=True)
Out[9]:
CompletedProcess(args="echo 'hello world!' > myfile.txt", returncode=0)
In [10]:
!cat myfile.txt
hello world!

基本命令:cat¶

  • cat filename:打印文件filename的内容。
  • 所以cat就像echo,但它接受文件名作为参数,而不是字符串。
In [11]:
subprocess.run("cat myfile.txt", shell=True)
hello world!
Out[11]:
CompletedProcess(args='cat myfile.txt', returncode=0)

文件基本命令¶

  • mkdir
    • mkdir dirname:如果不存在,则创建一个名为dirname的新目录
  • mv
    • mv file1 file2:“移动”file1到file2,覆盖file2。
    • 如果file2是一个目录,这将把file1放在那个目录里
  • cp
    • cp file1 file2:类似于mv,但创建一个名为file2的file1副本
  • rm
    • rm filename:删除文件filename。
In [19]:
subprocess.run("mkdir mydir", shell=True)
Out[19]:
CompletedProcess(args='mkdir mydir', returncode=0)
In [37]:
!ls -d mydir
mydir
In [35]:
subprocess.run("cp myfile.txt mydir", shell=True)
!ls -l mydir
total 0
-rwxrwxrwx 1 pingjianding pingjianding 13 Nov  4 10:13 myfile.txt
In [38]:
subprocess.run("mv mydir/myfile.txt image", shell=True)
Out[38]:
CompletedProcess(args='mv mydir/myfile.txt image', returncode=0)
In [41]:
subprocess.run("cp myfile.txt mydir", shell=True)
!ls -l mydir
print("*********************************************")
subprocess.run("rm mydir/myfile.txt", shell=True)
!ls -l mydir
total 0
-rwxrwxrwx 1 pingjianding pingjianding 13 Nov  4 10:16 myfile.txt
*********************************************
total 0

Shell脚本编程¶

  • Shell程序的执行
    • sh <example.sh 或 bash <example.sh
    • sh example.sh 或 bash example.sh
    • path/example.sh (当前文件夹下使用./example.sh,指定解释器的路径)

通配符¶

  • *(星号) 如file*、 *.fa #任意个任意字符
  • ?(问号) 如file?.txt #1个任意字符
  • [字符集合] 如[13579] [agh] #集合中的任意一个字符
  • [字符范围] 如[0-9] [a-z] #范围中的任意一个字符
  • !或^ 如file[!3-9] #除了某范围或集合中的任意一个字符
In [42]:
subprocess.run("ls *.ipynb", shell=True)
lecture01.ipynb
lecture02.ipynb
lecture03.ipynb
lecture04.ipynb
lecture05.ipynb
lecture06.ipynb
lecture07.ipynb
lecture08-2.ipynb
lecture08.ipynb
lecture09-2.ipynb
lecture09.ipynb
lecture10-Copy1.ipynb
lecture10.ipynb
lecture11.ipynb
lecture12.ipynb
test.ipynb
Out[42]:
CompletedProcess(args='ls *.ipynb', returncode=0)
In [43]:
subprocess.run("ls lecture??.ipynb", shell=True)
lecture01.ipynb
lecture02.ipynb
lecture03.ipynb
lecture04.ipynb
lecture05.ipynb
lecture06.ipynb
lecture07.ipynb
lecture08.ipynb
lecture09.ipynb
lecture10.ipynb
lecture11.ipynb
lecture12.ipynb
Out[43]:
CompletedProcess(args='ls lecture??.ipynb', returncode=0)
In [44]:
subprocess.run("ls lecture[!0][0-9].ipynb", shell=True)
lecture10.ipynb
lecture11.ipynb
lecture12.ipynb
Out[44]:
CompletedProcess(args='ls lecture[!0][0-9].ipynb', returncode=0)

正则表达式¶

  • grep(Global Regular Expression Print),用于搜索文本文件中的特定模式或字符串。它可以根据正则表达式搜索文件中的内容,并打印出匹配的行。
In [45]:
subprocess.run("cat nucleic_acid", shell=True)
DNA
RNA
mRNA
tRNA
rRNA
snRNA
snoRNA
miRNA
lncRNA
Out[45]:
CompletedProcess(args='cat nucleic_acid', returncode=0)
In [95]:
subprocess.run("grep '[mt]RNA' nucleic_acid", shell=True)
mRNA
tRNA
Out[95]:
CompletedProcess(args="grep '[mt]RNA' nucleic_acid", returncode=0)

通配符与正则表达式的区别¶

  • 通配符是用来匹配文件名的, 是完全匹配;
  • 正则表达式是用来匹配文件中的文本的, 是包含匹配, 如grep查找一个正则表达式时, 任意包含该表达式的行都会显示出来。

引号¶

  • 双引号:
    • 由双引号括起来的字符, 除 $、 `和 \ 外都作为普通字符处理
  • 单引号:
    • 由单引号括起来的字符除\外都作为普通字符处理
  • 反引号:
    • 反引号括起来的字符shell作为命令处理
In [ ]:
## 案例: 双引号内的$作为变量开始的标志
subprocess.run("""LONGNAME=peter; 
               echo "Hello $LONGNAME";""", shell=True)
Hello peter
Out[ ]:
CompletedProcess(args='LONGNAME=peter; \n               echo "Hello $LONGNAME";', returncode=0)
In [108]:
subprocess.run("""LONGNAME=peter; 
               echo 'Hello $LONGNAME';""", shell=True)
Hello $LONGNAME
Out[108]:
CompletedProcess(args="LONGNAME=peter; \n               echo 'Hello $LONGNAME';", returncode=0)

反引号¶

  • 反引号表示命令替换, Shell在执行命令行之前, 先用反引号中的命令的执行结果替换反引号及其中的内容。
In [120]:
subprocess.run("cat example.sh; ", shell=True)
print("*******************************************************")
subprocess.run("bash example.sh;", shell=True)
#!/bin/bash # 指定解释器的路径
echo "The current time is `date`;"
*******************************************************
The current time is Sat Nov  2 23:58:40 CST 2024;
Out[120]:
CompletedProcess(args='bash example.sh;', returncode=0)

命令组合符¶

  • 无条件命令组合符
    • 管道:
      • cat fern | grep sinensis #命令1的输出作为命令2的输入
    • 顺序执行:
      • cd plant; touch rose.txt #依次执行命令1和命令2
        • touch用于创建新的空文件或者修改现有文件的时间戳
  • 条件命令组合符
    • 逻辑与:
      • touch cow && rm cow #如果命令1执行成功则执行命令2
    • 逻辑或:
      • test -e animal || mkdir animal #如果命令1执行不成功再执行命令2

Shell变量类型¶

  • 用户自定义变量
  • 位置变量
    • 位置变量是指那些用来存储传递给脚本的参数的变量。
  • 环境变量

自定义变量: 赋值¶

  • 变量赋值
    • 变量名=字符串, 如:
      • myfile=tmp/c.fa #等号两边不能有空格
      • mypath=/home/xiezy/$myfile #字符串中可以包含变量
      • name=“Zhang San” #字符串中有空格要用引号
  • 命令替换(将命令执行结果赋值给变量)
    • current_dir=`pwd`
    • current_dir=$(pwd)
In [133]:
!current_dir=`pwd`; echo $current_dir;
/mnt/c/Users/ASUS/Desktop/PPT

自定义变量: 数组¶

  • bash只提供一维数组
  • 数组大小没有限定
  • 数组的下标从0开始
  • 赋值:
    • city[0]=Beijing
    • week=(Mon Tue Sun)

变量直接引用¶

  • $var
    • name=peter
    • echo $name
    • echo ${name}
  • ${var}
    • name=first
    • echo ${name}_name #此处大括号不能省略
In [139]:
!name=peter; echo $name;
!name=peter; echo "Hello $name";
!name=peter; echo "Hello ${name}_name";
peter
Hello peter
Hello peter_name

数组引用¶

  • 数组第i个元素
    • ${array[i]}
  • 数组所有元素
    • ${array[*]}
    • ${array[@]}
  • 数组第i个元素的长度
    • ${#array[i]}
  • 数组元素的个数
    • ${#array[*]}
    • ${#array[@]}
In [56]:
%%bash
arr=(Mon Tue Wes)
echo ${arr[0]}
echo ${arr[*]}
echo ${#arr[0]}
echo ${#arr[*]}
Mon
Mon Tue Wes
3
3

算数运算¶

In [57]:
%%bash
# 整数运算,(())
i=3;
((i=i+1)); echo $i;
j=$((i*3)); echo $j;

# 整数运算,let
let i=i+1; echo $i;

# expr
expr 1 + 1  #运算符两侧需有空格

# $[]
j=$[i*2]; echo $j;
4
12
5
2
10

控制结构¶

  • 顺序执行: 换行或分号
  • 判断: if、 case
  • 循环: for、 while、 until、 select
In [ ]:
%%bash
# if语句
if test -f lecture10.ipynb
then
    echo “File exists!”
else
    echo “File does not exist!”
fi
“File exists!”
In [58]:
%%bash

week=Sunday
case $week in
    Saturday|Sunday) 
        echo “Weekend”
        ;;
    Monday|Tuesday|Wednesday|Thursday|Friday) 
        echo “Work day”
        ;;
    *) 
        echo “Unknown date”
        ;;
esac
“Weekend”

for语句: 值表形式¶

In [59]:
%%bash

person=(Ding Luo)
for i in "${person[@]}" 
do
    echo $i
done
Ding
Luo
In [30]:
%%bash

for i in {1..3} #注意是两对小括号
do
    echo $i
done
1
2
3

shell函数示例¶

In [61]:
%%bash

function add() {
  echo $(($1 + $2))
}

# 调用函数
result=$(add 2 3)
echo "结果是: $result"
结果是: 5