Linux命令行与shell脚本编程大全第三版 学习笔记

0. 注意Linux中一切皆文件,本文中的文件指的是广义的文件,包括文件、目录、硬件设备 等等。

1. 初识Linux shell


1.1, Linux分为四个部分: Linux内核,GNU工具集,图形化桌面环境,应用软件

1.1.1, Linux内核主要负责四种功能:系统内存管理,软件程序管理,硬件设备管理,文件系统管理

1.1.1.1, 物理内存&虚拟内存;交换空间(swap space),换入(swapping in), 换出(swapping out)

1.1.1.2, 进程;init进程;`/etc/initab` (TODO:被systemd取代了); runlevel(共有5个运行等级);

1.1.1.3,任何与Linux系统通信的硬件设备,都需要在Linux内核代码中加入驱动程序代码;内核模块;Linux系统将硬件设备当成特殊的文件(`Linux系统一切皆文件`),称为设备文件,分为三类(1字符型设备文件,2块设备文件,3网络设备文件);Linux系统为系统上的每个设备都创建了一种称为节点的特殊文件,每个节点都有唯一的数值对供Linux内核标识它,数值对包含一个主设备号和一个次设备号。

1.1.1.4, Linux支持的文件系统类型(ext, ext4, msdos,ntfs,proc,vfat[即fat32]....);Linux内核采用虚拟文件系统(Vitual File System)作为和每个文件系统交互的接口。

1.1.2,GNU(GNU's Not Unix)是GNU组织在开源软件(Open Source Software,OSS)理念下模仿Unix操作系统开发的一系列标准的计算机系统工具;Linux内核和GNU工具结合在一起就构成了Linux操作系统,也叫GNU/Linux操作系统。

1.1.2.1, GNU核心工具包(coreutils软件包)由三部分构成:用以处理文件的工具,用以操作文本的工具,用以管理进程的工具。

1.1.2.2, shell是GNU工具集中的一部分,Linux发行版默认的shell一般是GNU bash shell,这是GNU开发的作为 标准Unix Shell--Bourne Shell(开发者名字命名)的替代品,bash即Bourne Again Shell;其他shell类型。

1.1.3,X.org等软件包实现了一套软件X Windows,XWondows 软件是直接和显卡和显示器打交道的底层程序, 用以产生图形化显示环境,建立在XWindows系统软件之上的桌面环境可以供用户操作文件或开启程序;比较流行的Linux桌面环境有:KDE(K DeskTop Environment), GNOME(the GNU Network Object Model Environment),Unity桌面环境(Ubuntu开发),其他低内存消耗的Linux桌面环境;桌面环境都配有各种应用软件。


 1.2,Linux的4个组成部分汇集起来组成一个易于安装的包就是Linux发行版;不同的Linux发行版可归为三类:完整的Linux发行版,特定用途的发行版,LiveCD测试发行版。

1.2.3, 多数PC可以从CD启动而不是必须从标准硬盘启动,基于这点,一些Linux发行版创建了含有Linux样本系统(称为Linux LiveCD)的可引导CD,Linux LiveCD是一种无需将Linux安装到硬盘就能体验Linux的发行版



 

2. 走进Shell

2.1,终端

  • 不涉及GUI的终端:控制台终端(ctrl+alt+f2~f7)属于虚拟终端(运行在内存中),可以使用setterm -background yellow 等命令设置控制台终端样式;
  • GUI中的终端:桌面环境下的终端属于仿真终端;

3. 基本的Bash Shell 命令

3.1,启动shell

3.1.1, GNU bash shell 能够提供对Linux系统的交互式访问。它是作为普通程序运行的。除了Bash Shell还有一些其他的shell,如dash shell, tcsh等等。用户登录终端时启动的shell类型取决于用户账户如何配置, `/etc/passwd` 文件包含了系统所有用户账户列表以及每个用户的基本配置信息,例如其中一个用户条目:`tonux:x:1000:1000:Tonux:/home/tonux:/bin/bash` ,每个条目有七个字段,字段之间用分号分开,每个字段赋予用户账户某些特定特性,最后一个字段指定了用户使用的shell程序。

3.1.2,Bash Shell是在用户登录系统时自动启动的,但是是否会出现shell命令行界面(CLI)则依赖于使用的登录方式。如果是采用虚拟化终端登录,CLI命令提示符会自动出现,可以输入shell命令;如果是通过图形化桌面环境登录Linux的话,则需要启动一个图形化终端仿真器来访问shell 命令行界面(CLI)。


3.2,bash shell 的默认提示符是美元符号$, 可以修改。


3.3,bash手册

3.3.1, man 命令用来访问存储在Linux系统上的手册页面。如果养成了阅读手册的习惯,尤其是阅读第一段或是 DESCRIPTION 部分的前两段,最终你会学到各种技术行话,手册页也会变得越来越有用。

3.3.2,`man -k keyword` 可以查找关键词相关的命令,忘记命令具体名称时可以使用此技巧。

3.3.3, man命令手册分为9个模块,有的命令在不同的模块都有介绍,比如 hostname 命令,在第一个模块和第七个模块都有介绍。想要查看特定模块内的内容,可以使用`man 7 hostname`.

3.3.4,查看9个模块的介绍,使用如下命令: `man 1 intro`, `man 2 intro`......,各模块的类别信息如下:

模块号 所涵盖的内容
1 可执行程序或shell命令
2 系统调用
3 库调用
4 特殊文件
5 文件格式与约定
6 游戏
7 概览、约定及杂项
8 超级用户和系统管理员命令
9 内核例程

 

 

 

 

 

 

 

 

 

 

 

 

 3.3.5,除了man 命令由于查看帮助手册外,还有如下命令可查看shell命令的帮助信息:

  • 1.  info 命令也能查看命令帮助信息,info命令查看的信息更新更全,但太繁琐;
  • 2,help命令,built-in 命令需要通过 help命令查看,如 help cd, help history等等, help help 可以查看help本身的相关信息;
  • 3,还可以使用命令的 --help 或 -help 或 -h 选项查看帮助信息, 如 cp --help ;

3.4, 浏览文件系统

3.4.1, Linux文件系统,

  • 在Windows中,PC上安装的物理驱动器决定了文件的路径名。Windows会为每个物理磁盘驱动器分配一个盘符,每个驱动器都会有自己的目录结构,以便访问存储其中的文件。

  • Linux则采用了一种不同的方式。Linux将文件存储在单个目录结构中,这个目录被称为虚拟目录(virtual directory)。虚拟目录将安装在PC上的所有存储设备的文件路径纳入单个目录结构中。Linux虚拟目录结构只包含一个称为根(root)目录的基础目录。在Linux PC上安装的第一块硬盘称为根驱动器。根驱动器包含了虚拟目录的核心,其他目录都是从那里开始构建的。Linux会在根驱动器上创建一些特别的目录,我们称之为挂载点(mount point)。挂载点是虚拟目录中用于分配额外存储设备的目录。虚拟目录会让文件和目录出现在这些挂载点目录中,然而实际上它们却存储在另外一个驱动器中。

  • https://zhidao.baidu.com/question/1645248554140989660.html
  • https://www.cnblogs.com/sammyliu/p/5729026.html

表3-3 常见Linux目录名称
目录   用途
/ 虚拟目录的根目录。通常不会在这里存储文件
/bin 二进制目录,存放许多用户级的GNU工具
/boot 启动目录,存放启动文件
/dev 设备目录,Linux在这里创建设备节点
/etc 系统配置文件目录
/home 主目录,Linux在这里创建用户目录
/lib 库目录,存放系统和应用程序的库文件
/media 媒体目录,可移动媒体设备的常用挂载点
/mnt 挂载目录,另一个可移动媒体设备的常用挂载点
/opt 可选目录,常用于存放第三方软件包和数据文件
/proc 进程目录,存放现有硬件及当前进程的相关信息
/root root用户的主目录
/sbin 系统二进制目录,存放许多GNU管理员级工具
/run 运行目录,存放系统运作时的运行时数据
/srv 服务目录,存放本地服务的相关文件
/sys 系统目录,存放系统硬件信息的相关文件
/tmp 临时目录,可以在该目录中创建和删除临时工作文件
/usr 用户二进制目录,大量用户级的GNU工具和数据文件都存储在这里
/var 可变目录,用以存放经常变化的文件,比如日志文件

3.4.2,`cd`, `pwd(present working directory)`


 3.5, 文件和目录列表

3.5.1,`ls 命令`

  • ls -F 用以区分文件类型:目录后加/, 可执行文件加 *,软连接加@,
  • ls -d 只列出目录本身的信息,不列出其中的内容,
  • ls -i 显示文件/目录的 inode编号(文件或目录的inode编号是一个用于标识的唯一数字,这个数字由内核分配给文件系统中的每一个对象。)
  • ls -a 列出隐藏文件
  • ls -R 递归列出子目录
  • ls -l  显示长列表, 输出第一行表示目录中包含的总块数。显示的时间是最后一次内容修改的时间,相当于选项 --time=mtime (modify time)

     文件类型,比如目录( d )、文件( - )、字符型文件( c )或块设备( b );
     文件的权限(参见第6章);
     文件的硬链接总数;
     文件属主的用户名;
     文件属组的组名;
     文件的大小(以字节为单位);
     文件的上次修改时间;
     文件名或目录名。

  • ls -ul 显示的时间是访问时间,-u 相当于 --time=atime (access time)
  • ls -cl 显示的时间是状态改变时间, -c相当于--time=ctime (change time)
  • `ls -l 过滤器`,元字符通配符(metacharacter wildcards)
    • 问号( ? )代表一个字符;
    • 星号( * )代表零个或多个字符;
    • [ai],[a-i],[!a]

3.6,处理文件

3.6.1,创建文件, `touch`

  • 访问时间[ access time ], 读取一次文件内容,便会将access time 更新为当前系统时间. 如less/more命令会更新access time, 但是ls, stat命令不会修改access time;,注意测试时发现访问时间始终显示的是文件被修改后第一次访问的时间,不改变文件的情况下访问文件后 访问时间并不更新。
  • 修改时间[ modify time],对文件内容修改一次便会更新该时间; 
  • 状态改变时间[ change time ], 更改文件的属性便会更新该时间;
  • `stat filename` 查看文件详细信息

3.6.3,`cp`:     cp source destination

  • source 和 destination 参数都是文件名时, cp 命令将源文件复制成一个新文件,并且以destination 命名。新文件就像全新的文件一样,有新的修改时间。默认覆盖同名文件。加上`-i`参数可以询问是否覆盖, 只有回答y才会继续覆盖文件。

3.6.4, 文件链接 

  • 链接是目录中指向文件真实位置的占位符。在Linux中有两种不同类型的文件链接: 1,符号链接(软连接)symbolic link; 2,硬链接 hard link;
  • 符号链接就是一个实实在在的文件,它指向存放在虚拟目录结构中某个地方的另一个文件。符号链接和其指向的文件是两个独立的文件。使用ls -l查看可以看到两个文件大小并不一致,使用ls -il查看发现两个文件的inode编号也不一样。
    • `ln -s targetFile symbolicLink`
  • 硬链接会创建独立的虚拟文件,其中包含了原始文件的信息及位置。但是它们从根本上而言是同一个文件。引用硬链接文件等同于引用了源文件,但是删除时可以分别删除任何一个文件而不会影响另外一个。注意只能对位于同一个物理存储设备的文件创建硬链接,不同的物理存储设备中的文件只能创建符号链接。
    • ln targetFile hardLink

3.6.5,移动文件、重命名文件

  • `mv 命令`可以将文件和目录移动到另一个位置或重新命名,可以移动位置的同时重命名。mv命令只移动或重命名文件,文件的inode编号和时间戳保持不变

  • `mv source destination`, -i 交互式提醒是否覆盖
  • mv 移动目录时,不需要加递归参数-R

3.6.6,删除文件

  • `rm -i fileName`, -i 命令参数提示你是不是要真的删除该文件。bash shell中没有回收站或垃圾箱,文件一旦删除,就无法再找回。因此,在使用 rm 命令时,要养成总是加入 -i 参数的好习惯。
  • ·rm -f fileName` -f参数强制删除。小心为妙!

3.7,处理目录

3.7.1, 创建目录

  • `mkdir newDirName`
  • `mkdir -p dir1/dir2/dir3...`  同时创建多个目录和子目录,需要加入 -p 参数

3.7.2,删除目录

  • `rmdir dirName` rmdir命令只允许删除空目录。
  • rmdir 并没有 -i 选项来询问是否要删除目录。这也是为什么说 rmdir 只能删除空目录还是有好处的原因。

  • `rm -ri myDir`  也可以在整个非空目录上使用 rm 命令。使用 -r 选项使得命令可以向下进入目录,删除其中的文件,然后再删除目录本身。

  • 对 rm 命令而言, -r 参数和 -R 参数的效果是一样的。但是shell命令中,不同大小写的参数一般代表不同的功能。
  • `rm -rf dirName`命令既没有警告信息,也没有声音提示。这肯定是一个危险的工具,尤其是在拥有超级用户权限的时候。务必谨慎使用,请再三检查你所要进行的操作是否符合预期。


 

3.8,查看文件内容

3.8.1,查看文件类型

  • ·file fileName·  file命令能够探测文件的内部,并确定文件的类型。

3.8.2,查看整个文件

  • cat 命令
    • ·cat fileName· 查看整个文件的内容
    • `cat -n fileName` 添加行号
    • ·cat -b fileName· 只给有文本的行添加行号
    • ·cat -T fileName· 将制表符用^I 代替
  • more 命令
    • `more fileName` 一次显示一屏文本
  • less 命令: less命令实际上是more命令的升级版,less命令的命名实际上是个文字游戏(来自俗语“less is more”),能够实现在文本文件中前后翻动,而且还有一些高级搜索功能。
    • ·less fileName· 

3.8.3,查看部分文件

  • tail 命令
    • `tail fileName` 默认显示文件的最后10行;
    • ·tail -n fileName· 显示文件最后 n 行;
    • ·tail -f fileName· -f 参数是 tail 命令的一个突出特性。它允许你在其他进程使用该文件时查看文件的内容。tail 命令会保持活动状态,并不断显示添加到文件中的内容。这是实时监测系统日志的绝妙方式。
  • head 命令
    • ·head fileName· 默认显示文件的头10行
    • 文件头部信息一般不会改变,所以head命令不支持 -f 参数;

 



4. 更多的Shell 命令

4.1,监测程序

4.1.1, 探查进程 (ps 命令)

  • ps命令有两个版本:Unix风格参数(单破折号参数) 和 BSD(Berkeley software distribution,BSD)风格参数(不带破折号), 后来GNU开发人员又加入了另外一些长参数(双破折号),这些长参数可以配合前面任意一种风格使用。不同风格的参数显示的信息也有所差别。
  • ·ps· ps 命令默认只会显示运行在当前控制台下的属于当前用户的进程。

4.1.1.1, Unix参数风格的ps, 常用参数如下

  • ·ps -e·   -e 参数指定显示所有运行在系统上的进程;
  • ·ps -f` -f 参数则扩展了输出,这些扩展的列包含了有用的信息。
    • UID:启动这些进程的用户
    •  PID:进程的进程ID。
    •  PPID:父进程的进程号(如果该进程是由另一个进程启动的)。
    •  C:进程生命周期中的CPU利用率。
    • STIME:进程启动时的系统时间
    •  TTY:进程启动时的终端设备。
    •  TIME:此进程累计消耗的CPU时间
    • CMD:启动的程序名称
  • ·ps -l` -l参数获取更多字段
    •  F :内核分配给进程的系统标记。
    • S :进程的状态(O代表正在运行;S代表在休眠;R代表可运行,正等待运行;Z代表僵化,指进程完成了,但父进程没有响应;T代表停止)。
    •  PRI :进程的优先级(越大的数字代表越低的优先级)。
    •  NI :谦让度值用来参与决定优先级
    •  ADDR :进程的内存地址
    •  SZ :假如进程被换出,所需交换空间的大致大小
    •  WCHAN :进程休眠的内核函数的地址。

4.1.1.2, BSD风格的参数

  • ·ps l· l参数与unix风格输出不同的字段如下
    • VSZ:进程在内存中的大小,以千字节(KB)为单位。
    • RSS:进程在未换出时占用的物理内存。
    •  STAT:代表当前进程状态的双字符状态码。

4.1.1.3, GNU长参数

  • ·ps --forest·  --forest 参数会显示进程的层级信息,并用ASCII字符绘出可爱的图表

4.1.2,实时监测进程

  • 第一行显示了当前时间、系统的运行时间、登录的用户数以及系统的平均负载。平均负载有3个值:最近1分钟的、最近5分钟的和最近15分钟的平均负载。值越大说明系统的负载越高。通常,如果系统的负载值超过了2,就说明系统比较繁忙了。

  • 第二行显示了进程概要信息—— top 命令的输出中将进程叫作任务(task):有多少进程处在运行、休眠、停止或是僵化状态(僵化状态是指进程完成了,但父进程没有响应)。

  • 默认情况下, top 命令在启动时会按照 %CPU 值对进程排序。按 ·P`手动按CPU排序,按·M·手动按内存排序,按·f`选择排序字段,按·d`改变轮询间隔,还有一些其他按键参数,自己去试。

4.1.3,结束进程

  • 在Linux中,进程之间通过信号来通信。进程的信号就是预定义好的一个消息,进程能识别它并决定忽略还是作出反应。进程如何处理信号是由开发人员通过编程来决定的。大多数编写完善的程序都能接收和处理标准Unix进程信号。

  • ·kill -l ·列出所有的信号
  • ·kill pid` 默认向进程pid发送一个TERM(15)的信号。
  • ·kill -9 pid` = `kill -kill pid`
  • `killall xxxx`  killall 命令非常强大,它支持通过进程名而不是PID来结束进程。 killall 命令也支持通配符,这在系统因负载过大而变得很慢时很有用。慎用!

4.1.4,


4.2,监测磁盘空间

4.2.1, 挂载存储媒体

  • Linux文件系统将所有的磁盘都并入一个虚拟目录下。在使用新的物理磁盘之前,需要把它放到虚拟目录下。这项工作称为挂载(mounting)。

  • ·mount` 默认情况下, mount 命令会输出当前系统上挂载的设备列表。
  • `mount device directory` 
  • ·umount [device | directory]· umount 命令支持通过设备文件或者是挂载点来指定要卸载的设备。如果有任何程序正在使用设备上的文件,系统就不会允许你卸载它。可以使用lsof命令查看占用设备的程序
  • ·lsof · 用法见 此博文,lsof是一个很强大的命令。
  • df 命令可以让你很方便地查看所有已挂载磁盘的使用情况.

  •  ·df -h` -h人性化阅读

  •  du 命令可以显示某个特定目录(默认情况下是当前目录)的磁盘使用情况。

  • `du` 显示当前目录下各个子目录(包括子目录的子目录)的占用空间大小

  • `du dir` 显示指定目录下各个子目录(包括子目录的子目录)的占用空间大小
  • `du -a` 显示所有文件占用大小(包括文件,目录,子目录,子目录下的文件)
  • ·du fileName· 显示指定文件占用大小
  • ·du -s dir· 只显示指定目录(不包含子目录)占用空间大小
  • ·du -S dir· 显示指定目录及其子目录占用空间大小,但是父目录大小计算时不包含子目录的大小
  • ·du -c dir· 显示指定目录(及其子目录)占用空间大小,并额外显示目录的总大小
  • ·du -b/-k/-m· 显示大小单位为 byte/kb/mb
  • `du -h`显示单位为 human-readable, 以K,M,G为单位,提高信息的可读性,换算单位为1024。
  • ·du -H`  同-h参数,但是换算单位为1000;
  • ·du -sh *· ,常用命令组合,显示当前目录下 所有文件,目录(不包含子目录)占用大小
  • ·du -sh * | sort -nr` 按占用空间大小倒序排列
    ·

4.3,处理数据文件

  • ·sort file· 默认对文件中的所有行进行排序,默认排序规则是按照默认语言的排序规则,会将数字识别成文本
  • ·sort file file ...` sort 支持对多个文件的排序(合并内容后排序)
  • ·sort -n file` 将数字识别成数字而不是文本
  • ·sort -r file` 倒序排
  • ·sort -t ":" file ` 用冒号":" 分割file中的内容,常常与-k参数连用
  • `sort -k pos1[,pos2] file` 排序从pos1开始,如果指定了pos2则到pos2结束。注意此参数必须与 -t 参数一起用才有意义,

4.4, 搜索数据

关于grep工具涉及到的正则表达式,和平常的正则表达式规则有一些差异,主要是正则表达式有好几个流派:PCRE(Perl Compatible Regular Expression,这也是平常用的正则),POSIX(posix可以看做是unix操作系统的规范,防止不同版本差异过大带来的不便)规则下的正则表达式(又分成2类:BRE :basic regular expression; ERE :extended regular expression,虽然命名叫扩展,但并不要求兼容bre,实际是自成一派),具体可参阅这篇文章:Linux/Unix 工具与正则表达式的 POSIX 规范 。

  • ·grep [options]... pattern [file]...`  global(G) search regular expression(RE) and print out the line。 使用正则表达式搜索文本,并把匹配的行打印出来。
  • `grep pattern file1 file2 file3...` 可以在多个文件中查找;
  • ·grep -v pattern file· 反向搜索,输出不包含pattern的行;
  • ·grep -n pattern file` 显示匹配行所在的行号;
  • ·grep -c pattern file` 只显示匹配行的行数;
  • ·grep -e pattern1 -e pattern2 file` 使用-e参数指定多个匹配模式;
  • ·grep -o pattern file` 只输出匹配部分
  • ·grep -P pattern file`  pattern为Perl格式的正则表达式
  • ·grep -E pattern file` pattern为ERE格式的正则表达式,等同于egrep工具;
  • `egrep`
  • `fgrep`

4.5,压缩数据

  •  `gzip [options]... [file]...`
  • `gzip a.txt b.log` 将a.txt b.log压缩至a.txt.gz b.log.gz压缩文件中,注意是将每个文件分别压缩进不同的包里,源文件也不存在了。
  • ·gzip -r myDir` 递归将文件夹 myDir 中的所有文件压缩
  • ·gunzip a.txt.gz` 解压缩
  • ·gunzip -r myDir` 递归解压文件夹下的压缩包
  • ·zip / unzip· gzip 压缩率好于 zip

4.6,归档数据 (Tar 命令): 将许多文件一起保存至一个单独的磁带或磁盘归档,并能从归档中单独还原所需文件。tar命令为打包命令,可以结合gzip, bzip2等命令在打包的同时进行压缩。

  • `tar [options]... [file]....`
  • -c 新建打包文件, -t查看打包文件, -x解包打包文件,这三个参数互斥
  • -v 显示过程
  • -f 这个参数后面必须紧跟打包的包名,不能再有其他参数
  • `tar -cvf path/to/myTar.tar dir1 dir2 ...` 将目录dir1 dir2... 打包到 path/to/myTar.tar 包中
  • `tar -tf path/to/myTar.tar` 查看包中的内容
  • ·tar -xvf path/to/myTar.tar· 将myTar.tar包中的内容解包到当前目录(解包包括包内的目录结构)
  • ·tar -xvf path/to/myTar.tar dir/file· 只解包包中指定的文件 /dir/file, 也可以只解包包内某个目录。如果/dir/file在包内不存在,此命令会报错:dir/file: Not found in archive。
  • ·tar -xvf path/to/myTar.tar -C dir` -C参数指定解包目录,即将包中的所有内容(包含目录结构)解包到指定目录dir 中
  • `tar -xvf path/to/myTar.tar -C dir --strip-component NUMBER` --strip-component 参数可以指定一个数字来剥离包中的前导目录,·--strip-component 2· 即剥离前两层目录
  • ·tar -zcvf path/to/myTar.tar.gz dir1 dir2· -z参数在打包的同时调用gzip命令进行压缩,命名一般用 `.tar.gz 或 .tgz`来标志这是一个gzip压缩的tar包
  • ·tar -zxvf path/to/myTar.tar.gz` -z解压 tar.gz 包
  • ·tar -jcvf path/to/myTar.tar dir1 dir2· -j 参数在打包的同时调用bzip2 命令进行压缩,命名一般用`tar.bz2`来标志。
  • ·tar -jxvf ....` 同上,

4.7,



5. 理解 shell

5.1, 

  • `type -a command` 查看command 的位置, 是内置命令还是外部命令
  • ·which -a command` 查看command的位置

 5.2,

5.3,

5.4,

5.5,



6.使用Linux环境变量

6.1,bash shell用一个叫作环境变量(environment variable)的特性来存储有关shell会话和工作环境的信息(这也是它们被称作环境变量的原因)。这项特性允许你在内存中存储数据,以便程序或shell中运行的脚本能够轻松访问到它们。这也是存储持久数据的一种简便方法。

6.2,系统环境变量(包括系统的全局变量和局部变量)基本上都是使用全大写字母,以区别于普通用户的环境变量。变量名区分大小写。在涉及用户定义的局部变量时坚持使用小写字母,这能够避免重新定义系统环境变量可能带来的灾难。要查看全局变量,可以使用 env 或 printenv 命令。要显示个别环境变量的值,可以使用 printenv 命令,但是不能用 env 命令。

查看全局变量:全局环境变量对于shell会话和所有生成的子shell都是可见的。

  • `printenv`
  • `env`
  • ·printenv HOME· printenv 好像有些全局变量打印不出来,所以使用 echo $XXX 比较稳妥
  • ·env HOME` 报错
  • `echo $HOME` 必须加$符号
  • ·ls $HOME` 

查看局部变量: 局部变量只对创建它们的shell可见。Linux系统也默认定义了标准的局部环境变量。

  • ·set`  在Linux系统并没有一个只显示局部环境变量的命令。 set 命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量以及用户定义变量。

命令` env 、 printenv 和 set 之间的差异`很细微。 set 命令会显示出全局变量、局部变量以及用户定义变量。它还会按照字母顺序对结果进行排序。 env 和 printenv 命令同 set 命令的区别在于前两个命令不会对变量排序,也不会输出局部变量和用户定义变量。在这种情况下, env 和 printenv 的输出是重复的。不过 env 命令有一个 printenv 没有的功能,这使得它要更有用一些。

6.3,设置用户自定义局部变量

  • `my_variable=Hello` 变量、等号、值 之间不能有任何空格!!!
  • `my_variable="Hello World"` 如果值包含空格,必须用 单引号 或 双引号

6.4,设置用户自定义全局变量

  • 通过export命令可以将局部变量变成全局变量,变量名前面不需要加 $。
  • ·export my_variable`
  • 修改子shell中全局环境变量并不会影响到父shell中该变量的值,子shell甚至无法使用 export 命令改变父shell中全局环境变量的值。

6.5,删除环境变量

  • ·unset my_variable· unset命令删除环境变量, 不需要加$符号
  • 和修改变量一样,在子shell中删除全局变量后,你无法将效果反映到父shell中。

6.6,默认的 shell 环境变量

  •  `RANDOM`  返回一个0~32767的随机数(对其的赋值可作为随机数生成器的种子)
  • `PATH`  shell查找命令的目录列表,由冒号分隔

不是所有的默认环境变量都会在运行 set 命令时列出。尽管这些都是默认环境变量,但并不是每一个都必须有一个值

6.7,设置 PATH 环境变量

  • 当你在shell命令行界面中输入一个外部命令时(参见第5章),shell必须搜索系统来找到对应的程序。 PATH 环境变量定义了用于进行命令和程序查找的目录。

  • 如果命令或者程序的位置没有包括在 PATH 变量中,那么如果不使用绝对路径的话,shell是没法找到的。如果shell找不到指定的命令或程序,它会产生一个错误信息。

  • PATH 中各个目录之间是用冒号分隔的,可以把新的搜索目录添加到现有的 PATH 环境变量中, 你只需引用原来的 PATH 值,然后再给这个字符串添加新目录就行了: ·PATH=$PATH:/home/tonux/scripts`

  • 常把当前目录·.· 添加到PATH变量中: ·PATH=$PATH:.·
  • 对 PATH 变量的修改只能支持到退出或重启系统。

6.8,持久化 环境变量

6.8.1, 在你登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些文件叫做启动文件或环境文件。bash检查哪些启动文件取决于 你启动 bash shell 的方式。启动bash shell 有三种方式:

  • 登录时作为默认登录 shell , 即在文本模式下输入用户名密码,作为服务器的Linux基本都是这种方式;
  • 作为非登录shell 的交互式shell,即在图形桌面下启动一个bash shell,和人交互的shell
  • 作为运行脚本的非交互式shell,脚本中的命令启动的 bash shell

6.8.2, 登录shell

要留意的是有些Linux发行版使用了可拆卸式认证模块(Pluggable AuthenticationModules ,PAM)。在这种情况下,PAM文件会在bash shell启动之前处理,这些文件中可能会包含环境变量。PAM文件包括 /etc/environment 文件和 $HOME/.pam_environment 文件。PAM更多的相关信息可以在http://linux-pam.org中找到。

  • 作为 登录shell 启动时,bash shell会在以下几个地方查找命令和环境变量
    • `/etc/profile` 此文件是bash shell 作为登录shell时默认的的主启动文件。此文件中的命令可能会涉及到另外两个文件(目录): ·/etc/bash.bashrc· 和 `/etc/profile.d 目录`, 他们也会含有环境变量
    • 以下4个文件提供一个用户专属的启动文件来定义该用户所用到的环境变量,按以下顺序查找,运行第一个被找到的文件,余下的则被忽略(最后一个文件并不会被查找,因为~/.bashrc通常通过其他文件如 ~/.bash_profile 运行)
    • ·$HOME/.bash_profile·
    • `$HOME/.bash_login`
    • `$HOME/.profile`
    • `$HOME/.bashrc`

6.8.3,非登录交互shell

  • 作为交互式shell启动的bash shell 不会读取 /etc/profile 文件, 只会检查 ~/.bashrc 文件(经测试,每次打开一个bash shell 实例都会依次读取以下文件:`/etc/bashrc`, `~/.bashrc`, `~/.bash_profile`)。

6.8.4,非交互shell

  • 优先读取 一个全局环境变量 ·BASH_ENV`,如果此变量设置了一个文件,那么非交互shell 就会读取此被设置的文件中的命令作为环境变量。
  • 如果没有设置BASH_ENV,则此脚本运行时产生的shell的环境变量分为两种:
    • 如果不产生子 shell,那么就以当前shell的环境变量作为其环境变量, [注释:所谓的当前shell就是运行shell脚本的shell环境,即上面两种启动shell中的一种]
    • 如果产生了子shell,则会继承父shell中的全局环境变量(注意无法继承父shell的局部环境变量),【注释:所谓的当前shell就是运行shell脚本的shell环境,即上面两种启动shell中的一种】

6.8.5,持久化环境变量的方法

  • 对于系统上的所有用户持久化环境变量
    • 此时只针对于登录shell,由于所有登录用户都会访问 /etc/profile,所以可以将自定义需要持久化的变量存入此文件中,但是由于Linux发行版升级时会更新此文件,更新后所有自定义的变量都会消失。所以最好的实践是在 /etc/profile.d 目录下建立一个以 .sh 结尾的脚本文件。把所有新的或修改过的全局环境变量设置放在这个文件中。
  • 对于系统上的个人用户持久化环境变量
    • 对于登录shell 以及 交互式 shell, 存储个人用户永久性bash shell变量的地方是$HOME/.bashrc文件,

    • 对于非交互shell,如果设置了 BASH_ENV 环境变量,则个人用户持久化的地方就是此变量所设置的文件,如果没有设置则持久化的文件位置取决于脚本运行时启动的shell类型。

6.10,数组变量:数组变量在不同shell间的可移植性并不好,Linux脚本中很少用数组变量。

  • ·my_arr_variable=(1 2 3 4 5)` 注意bash shell 中数组定义时不是用逗号,而是用空格!!
  • ·echo $my_arr_variable· 只显示第零个元素1
  • ·echo ${my_arr_variable[2]}· 显示第3个元素3
  • ·echo ${my_arr_variable[*]}· 显示所有元素
  • ·unset my_arr_variable[1]· 删除数组中的第2个元素,删除后第二个元素位置值为空,但是索引依然还在!,即my_arr_variable[1] 为空
  • ·unset my_arr_variable· 删除整个数组。


7. 理解Linux文件权限

7.1,Linux用户系统

7.1.1, Linux安全系统的核心是用户账户。每个能进入Linux系统的用户都会被分配唯一的用户账户。用户对系统中各种对象的访问权限取决于他们登录系统时用的账户。

7.1.2, `/etc/passwd` 文件存放了系统上所有用户的信息。/etc/passwd文件的字段包含了如下信息:

  •  登录用户名
  •  用户密码
  •  用户账户的UID(数字形式)
  •  用户账户的组ID(GID)(数字形式)
  •  用户账户的文本描述(称为备注字段)
  •  用户HOME目录的位置
  •  用户的默认shell

root:x:0:0:root:/root:/bin/bash

www:x:1000:1000::/home/www:/bin/bash

eiduo:x:1008:1009::/home/eiduo:/bin/bash

root用户账户是Linux系统的管理员,固定分配给它的UID是 0 。就像上例中显示的,Linux系统会为各种各样的功能创建不同的用户账户,而这些账户并不是真的用户。这些账户叫作系统账户,是系统上运行的各种服务进程访问资源用的特殊账户。所有运行在后台的服务都需要用一个系统用户账户登录到Linux系统上。Linux为系统账户预留了500以下的UID值。有些服务甚至要用特定的UID才能正常工作。

 /etc/passwd文件中的密码字段都被设置成了x。在早期的Linux上,/etc/passwd文件里有加密后的用户密码。但鉴于很多程序都需要访问/etc/passwd文件获取用户信息,这就成了一个安全隐患。

现在,绝大多数Linux系统都将用户密码保存在另一个单独的文件中(叫作shadow文件,位置在/etc/shadow)。只有特定的程序(比如登录程序)才能访问这个文件。

7.1.3, `/etc/shadow` 文件:/etc/shadow文件对Linux系统密码管理提供了更多的控制。只有root用户才能访问/etc/shadow文件,这让它比起/etc/passwd安全许多。

eiduo:$6$knAbzvfw$VYq2ZjwSzy4f/2afcWOcnVFLigxwQY0PmtfnEEGj/Q3hEm745lwYV306.lFHuUkafFIToDtTlcFjLim3f5CX..:18184:0:99999:7:::

在/etc/shadow文件的每条记录中都有9个字段:

  •  与/etc/passwd文件中的登录名字段对应的登录名
  •  加密后的密码
  •  自上次修改密码后过去的天数密码(自1970年1月1日开始计算)
  •  多少天后才能更改密码
  •  多少天后必须更改密码
  •  密码过期前提前多少天提醒用户更改密码
  •  密码过期后多少天禁用用户账户
  •  用户账户被禁用的日期(用自1970年1月1日到当天的天数表示)
  •  预留字段给将来使用

7.1.4, 添加新用户 ·useradd· 

  • ·useradd·命令创建的新用户的的 系统默认值被设置在 `/etc/default/useradd`文件中。
  • ·useradd -D` 查看所用Linux系统中的这些默认值,即查看 `/etc/default/useradd` 的内容。
    • # /usr/sbin/useradd -D
      GROUP=100
      HOME=/home
      INACTIVE=-1
      EXPIRE=
      SHELL=/bin/bash
      SKEL=/etc/skel
      CREATE_MAIL_SPOOL=yes
      #
      
      在创建新用户时,如果你不在命令行中指定具体的值, useradd 命令就会使用 -D 选项所显示
      的那些默认值。这个例子列出的默认值如下:
        新用户会被添加到GID为 100 的公共组;
        新用户的HOME目录将会位于/home/loginname;
        新用户账户密码在过期后不会被禁用;
        新用户账户未被设置过期日期;
        新用户账户将bash shell作为默认shell;
        系统会将/etc/skel目录下的内容复制到用户的HOME目录下,目录下是bash shell环境的标准启动文件;
        系统为该用户账户在mail目录下创建一个用于接收邮件的文件。
  • 可以在 -D 选项后跟上一个指定的值来修改系统默认的新用户设置(即修改文件内容)。如,·useradd -D -s /bin/tsch· 
    • -b default_home 更改默认的创建用户HOME目录的位置
      -e expiration_date 更改默认的新账户的过期日期
      -f inactive 更改默认的新用户从密码过期到账户被禁用的天数
      -g group 更改默认的组名称或GID
      -s shell 更改默认的登录shell
  • 也可以在使用useradd命令具体创建一个用户时指定此用户的默认配置,各种参数如下:
    • ·useradd userName` 创建一个用户,默认不会创建HOME目录;
      ·useradd -m userName` -m参数会创建默认的HOME目录;
      -c comment 给新用户添加备注
      -d home_dir 为主目录指定一个名字(如果不想用登录名作为主目录名的话
      -e expire_date 用YYYY-MM-DD格式指定一个账户过期的日期
      -e expire_date 用YYYY-MM-DD格式指定一个账户过期的日期
      -f inactive_days 指定这个账户密码过期后多少天这个账户被禁用; 0 表示密码一过期就立即禁用, 1 表示禁用这个功能
      -g initial_group 指定用户登录组的GID或组名
      -G group ... 指定用户除登录组之外所属的一个或多个附加组
      -k 必须和 -m 一起使用,将/etc/skel目录的内容复制到用户的HOME目录
      -m 创建用户的HOME目录
      -M 不创建用户的HOME目录(当默认设置里要求创建时才使用这个选项)
      -n 创建一个与用户登录名同名的新组
      -r 创建系统账户
      -p passwd 为用户账户指定默认密码
      -s shell 指定默认的登录shell
      -u uid 为账户指定唯一的UID

7.1.5, 删除用户

  • ·userdel userName· 默认情况下,userdel 命令会只删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件。
  • `userdel -r userName` 加上-r 参数, userdel 会删除用户的HOME目录以及邮件目录。

7.1.6, 修改用户: Linux提供了一些不同的工具来修改已有用户账户的信息

  • ·usermod` 修改用户账户的字段,还可以指定主要组以及附加组的所属关系
  • `passwd`   修改已有用户的密码
    • 系统上的任何用户都能改自己的密码,但只有root用户才有权限改别人的密码。-e 选项能强制用户下次登录时修改密码。你可以先给用户设置一个简单的密码,之后再强制在下次登录时改成他们能记住的更复杂的密码。

  • `chpasswd` 从文件中读取登录名密码对,并更新密码。
  • ·chage· 修改密码的过期日期
  • ·chfn· 修改用户账户的备注信息
  • ·chsh· 修改用户账户的默认登录shell
  • 每种工具都提供了特定的功能来修改用户账户信息。usermod 命令是用户账户修改工具中最强大的一个。

7.1.7, ·finger userName· finger 命令可以非常方便地查看Linux系统上的用户信息。

  • 出于安全性考虑,很多Linux系统管理员会在系统上禁用 finger 命令,不少Linux发行版甚至都没有默认安装该命令。

7.2,Linux组

7.3, Linux文件权限

7.4, 改变权限和所属关系

7.5, 



8.



9.



10.



11.



12.



13.



14,

 

你可能感兴趣的:(Linux命令行与shell脚本编程大全第三版 学习笔记)