1 入门“自动驾驶”为什么要学习Linux命令?
自动驾驶项目Apollo和Autoware都是基于Linux操作系统开发的,此外,像机器人软件平台ROS同样是Linux系统下生长起来的。大家都选择Linux的原因是它不仅免费而且开源,任何人都可以优化完善,这让Linux变得安全而高效。反之,如果选择微软的Windows或者苹果的Mac OS操作系统开发自己的机器人或者自动驾驶项目,首先它们就不是一个工业级的实时操作系统,只是家用的办公游戏系统,而且你既不能查看优化它们的底层代码,也不能定制适配,出了问题只能求助于微软和苹果公司。谁也不想受制于人,所以在很多开发项目上都首选Linux。
别以为现在的操作系统都有图形化的界面你就以为动动鼠标就行了。在Linux环境中,大多数时候我们运行的程序没有可视化窗口,所以掌握常用的Linux命令很有必要,它会让你更容易调试这些程序,下面给出常用的命令。
2 系统命令
2.1 cd
cd
命令用来切换路径,来自于change directory的首字母。这可能是我们使用最多的命令了。如果你想返回home路径,直接打cd即可,后面什么都不加。
在Linux中,为了方便会用某些符号表示特定的文件夹,可以跟命令一起用,例如:
cd ~
表示切换到home/你的用户名
路径;
cd /
表示切换到根目录下,注意这里的/
前除了空格什么都不加。Linux的根目录就相当于Windows中的“我的电脑”,想了解这个路径下各文件夹都是干什么的,可以在网上搜“Ubuntu根目录下各文件夹的功能详细介绍”。
cd .
表示当前目录,当前目录就是这个终端窗口所处的路径下,当然输入这个命令,路径不会有任何变化。但是这不是说这个符号是没用的,我们在使用CMake编译程序代码时,有时会用CMake .
命令,其中的点就表示使用当前路径下的CMakeLists.txt文件进行编译构建。
cd ..
表示退回上一层路径,即cd
后面跟着一个空格再加两个点。而且它还可以连续使用,例如退回两层就是cd ../..
。我们在使用CMake编译程序代码时经常会用CMake ..
命令,其中的两个点就表示使用上一层路径下的CMakeLists.txt文件进行编译构建。
cd -
(减号)表示退回到你上一次进入的那个路径,相当于Windows中的后退按键,注意与cd ..
不同。
2.2 source
source
命令用来执行一个脚本文件,在ROS中你会经常使用它。它的简写是.
(也就是英文的句号),你要是比较懒可用这个点代替,效果是一样的。
2.3 export
export
命令用来设置环境变量。下图所示的例子就是设置了一个变量a
的值。然后,我们可以用echo命令查看变量的值(使用变量前面要加$
符号),看看有没有设置成功。注意这样设置的变量只在当前这个打开的终端中有效,你在其它终端中是找不到a
的。
2.4 history
history
命令很简单,用来显示你以前输入过的命令。如果你忘了某个命令怎么写,而记得以前输入过,就可以使用history命令查找。
2.5 clear
clear
命令跟MATLAB中的一样,用来清屏终端窗口。如果你懒得打字也可以按快捷键Ctrl+L(这里字母L大小写都可以)。
3 文件操作
3.1 新建文件
touch
命令用来新建一个文件,如下图所示的例子。
3.2 重命名文件
mv
命令用来移动一个文件,如果这个文件的目的地路径没变但是名字变了,就相当于重命名一个文件。所以,mv
命令也用于重命名,如下图所示。
3.3 复制文件
cp
命令用来复制文件,格式是cp 文件名 路径
,其中文件名就是你要复制的文件(如果同时复制多个文件就用空格隔开即可),路径就是你要复制到的目标文件夹。下图所示的例子先新建了两个文件:a.c和b.c,然后将它们复制到桌面路径下。
3.4 查找文件
find
命令用来查找一个文件,如下图所示的例子。中间的点表示在当前目录(包含子目录)下查找,-name
后面跟着你要找的文件名。
3.5 mkdir
mkdir
命令用于新建一个文件夹。如果想直接建立子文件夹(也就是文件夹中的文件夹),跟着个-p
即可。
4 性能监视
4.1 程序运行耗时统计
使用time
命令可以记录程序运行的时长,使用方法很简单,在平时运行程序的前面加上time
即可。下图所示的例子是一个1秒延时的程序,因此统计耗时应该在1秒左右,所以在real栏显示了程序实际耗时,很接近1秒。
4.1 CPU占用
使用top
命令可以了解CPU的使用情况,也可以找到进程号等信息。进程号就是最左面的一列,即写着PID的那列。
使用htop
命令可以查看实时刷新的CPU每个核的占用情况和进程信息,但是htop
不是Ubuntu默认安装的,需要使用sudo apt install htop
安装。要退出监视按q
键即可。
4.2 内存占用
free
命令显示操作系统总的内存和可用内存。后面跟着的-m
的意思是以MB为单位显示。如果你想看GB单位,换成-g
即可。Mem这一行表示内存,其中free这一列表示可用的内存,这里数字的单位都是MB,例如下图显示可用的内存还有20349MB。
4.3 硬盘占用
如果想知道硬盘的占用空间和剩余空间还有多少,可以用df -h
命令,出现的列表第三行就是系统的剩余可用空间,如下图所示的例子,硬盘总大小是196GB,已经占用了16GB,空闲的空间为171GB。
du
命令用于显示当前目录下的文件和文件夹所占用的硬盘空间。
5 用alias
重命名命令
如果一个命令你经常使用,但是它又比较长,而你懒得每次都打很多字,就可以把它重命名成一个短命令。打开home路径下的.bashrc文件,这个文件是个隐藏文件,所以如果你看不到按一下快捷键Ctrl+H,就会看到了。
以在ROS中经常使用的rostopic list
命令为例。在.bashrc文件的最后输入alias rl='rostopic list'
,然后保存关闭。新打开一个终端(注意修改.bashrc后要新开一个终端才开始有效),输入rl
就相当于rostopic list
命令啦,如下图所示。同样,我们可以给rostopic echo
、rosbag play
、catkin_make
等常用的命令都起个短名字,比如re
、rp
、cam
等等,只要你自己记住而且不与已有的命令重名就行了。
如果翻一翻.bashrc文件,你就会发现,系统已经自动给我们定义了一些短的别名,是不是很贴心。
6 高级命令
有些命令比上面那些用起来复杂一点,用的不是那么频繁。但是如果你掌握了还是会方便一些。
6.1 grep
grep
命令用来提取字符。举个例子就明白了,比如从文件a.txt中找出包含error
字符的那些行,即可以用下面的命令:
cat a.txt | grep 'error'
6.2 kill
kill
命令用来杀死一个进程。什么时候使用它呢?当你想让一个进程停止运行的时候就可以杀死它。举个例子,你启动了一个进程,这个进程可能包含好几个线程。有时候直接按Ctrl+C
无法一下杀死一个多线程进程,这时就可以用这个命令来干掉它了。我们举个例子,比如你运行了一个叫talker的进程(假设它是一个ROS节点,我们不管它有几个线程,因为都能杀死它)。然后我们用kill
让它结束。但是,kill
后面跟的是进程的编号(就是前面提到的PID数字),所以我们先用top
命令找到talker进程对应的PID,假设是123,然后在终端中输入kill 123
就能结束talker这个进程了。如果程序没有立即退出,那可以用kill -9 123
,加上-9
的意思是让进程立即中止运行,不需要任何等待。
你可能会说,有没有更方便一点的方法呢?有,我们用命令组合的方式来做,如下。
kill -9
ps -ef| grep talker | grep -v grep | awk '{print $2}'
这一长串命令是什么意思呢?我们来分析下,这是好几个命令组合起来得到的,中间用符号|
连接起来。符号|
的意思是管道,管道就是把前一个命令计算的结果传递给后面的命令,作为后面一个命令的输入。我们一个个看。第一个命令是ps -ef
,它的意思是显示所有进程的状态信息。但是它把系统里所有的进程都显示出来了,怎么找到我们想要的talker进程呢?就是用grep
查找。所以ps -ef| grep talker
的意思就是找到talker进程对应的状态信息。但是我们看到它找到了两个,其中一个是我们想要的,另一个是grep
的,我们不要后面这个。所以,用grep -v grep
去掉第二个,-v
的意思排除某些字符。然后,怎么从我们找到的状态信息里提取出进程的ID号呢?这时可以用awk
命令,awk '{print $2}'
命令的意思是拿出第二列对应的字符。所以ps -ef| grep talker | grep -v grep | awk '{print $2}'
命令的意思就是拿到一个叫talker进程的进程号(PID)。拿到以后,怎么给kill
命令呢。这时就要用倒单引号(就是键盘上esc下面那个按键)把刚才的命令括起来,命令运行的结果作为输入给kill
命令。
6.3 killall
killall
命令比kill
命令的杀伤范围更大。与kill
不同的是,killall
后面跟着的是程序的名称。假如你启动了多个同名的程序,那么这些程序都会被杀死。例如你开启了多个rviz窗口,在运行killall rviz
命令后,所有的rviz窗口都会关闭退出,而如果用kill
,则可以精确指定杀死某个(不响应)的rviz窗口,其它的窗口不受影响。
7 如何写脚本
上面都是一些单个的命令。有些时候我们要做的事需要很多命令组合起来才能完成,如果仍然重复地在终端中一遍遍地输入这些命令就太落后了。这个时候脚本就登场了,脚本就是一个可读文件,没有什么神秘的,你用记事本就能打开它。我们把很多命令放在脚本里,需要运行这么多命令的时候直接运行这个脚本就行了,这样是不是方便多了,简直是程序员提高工作效率的利器啊。没错,Apollo自动驾驶项目就是这么做的,在它的项目仓库下的scripts文件夹中就提供了很多脚本文件。大到安装编译Apollo系统,小到启动某个功能模块或者安装某个软件,都是通过脚本实现的。Apollo的程序员给我们提供了很好的学习模板,这么好的机会大家不要错过啊。
从一个脚本中运行另一个脚本,可以使用source
命令,例如在a.sh中使用source b.sh
即可运行b脚本。