《linux 鸟哥私房菜》

前言

一直以来没有系统学习过 linux ,今天通过《linux 鸟哥私房菜》这本书好好学习下。

用户和用户组

用户

Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统。
用户的账号一方面可以帮助系统管理员对使用系统的用户进行跟踪,并控制他们对系统资源的访问;另一方面也可以帮助用户组织文件,并为用户提供安全性保护。每个用户账号都拥有一个唯一的用户名和各自的口令。用户在登录时键入正确的用户名和口令之后,就能够进入系统和自己的主目录。

用户组

每个用户都有一个用户组,系统可以对一个用户组的所有用户进行集中管理。不同 Linux 系统对用户组的规定有所不同,如 Linux 下的用户属于与它同名的用户组,这个用户组在创建用户时同时创建。
用户组的管理涉及用户组的添加、删除和修改。组的增加、删除和修改实际上就是对 /etc/group 文件的更新。

Linux 文件属性

输入命令

ls -al

会输出当前目录下的所有文件的详细权限和属性。如下:

pwnki@LAPTOP-KETPO6R7:~$ ls -al
total 152
drwxr-xr-x 17 pwnki pwnki  4096 Jan  6 11:16 .
drwxr-xr-x  3 root  root   4096 Dec 20 21:46 ..
lrwxrwxrwx  1 pwnki pwnki    23 Dec 29 10:29 .aws -> /mnt/c/Users/86189/.aws
lrwxrwxrwx  1 pwnki pwnki    25 Dec 29 10:29 .azure -> /mnt/c/Users/86189/.azure
-rw-------  1 pwnki pwnki 17000 Jan  6 21:49 .bash_history
-rw-r--r--  1 pwnki pwnki   220 Dec 20 21:46 .bash_logout
-rw-r--r--  1 pwnki pwnki   200 Dec 28 16:21 .bash_profile
-rw-r--r--  1 pwnki pwnki  3889 Dec 28 16:21 .bashrc
drwxr-xr-x  8 pwnki pwnki  4096 Jan  4 20:24 .cache
drwx------  3 pwnki pwnki  4096 Dec 20 21:46 .config
drwxr-xr-x  4 pwnki pwnki  4096 Dec 29 00:37 ctf_xinetd
drwx------  4 pwnki pwnki  4096 Dec 29 10:48 .docker
drwxr-xr-x  3 pwnki pwnki  4096 Jan  6 11:18 free-libc
-rw-------  1 pwnki pwnki     3 Dec 23 11:29 .gdb_history
  1. 第一列代表这个文件的类型和权限。第一个字符代表文件类型,后面九个字符每三个一组,分别代表文件所有者的权限、同用户组的权限、其他非本用户组的权限。
  2. 第二列代表有多少文件名连接到此节点。
  3. 第三列表示这个文件(或目录)的“所有者账号”
  4. 第四列表示这个文件的所属用户组
  5. 第五列为这个文件的容量大小,默认为 B。
  6. 第六列为这个文件的创建日期或者是最近的修改日期。
  7. 第七列为文件名。

改变文件属性的权限

改变文件所属用户组命令 chgrp;改变文件所有者命令 chown;改变文件权限命令 chmod;具体用法参考 man 手册。

Linux 文件种类

任何设备在 Linux 下面都是文件,不仅如此,连数据通信的接口也有专门的文件负责。所以 Linux 有非常多的文件种类,如下:

  1. 文件种类

    • 普通文件。就是一般我们在进行访问类型的文件,依照文件内容,大致可分为三类。
      • 纯文本文件。这是 Linux 系统中最多的一种文件类型,称为纯文本文件是因为内容为我们可以直接读到的数据,例如数字、字母等。几乎只要我们可以用来作为设置的文件都属于这种文件类型。
      • 二进制文件。可执行文件就是这种格式的。
      • 数据格式文件。有些程序在运行的过程当中会读取某些特定格式的文件,那些特定格式的文件可以被称为数据文件。
  2. 目录

  3. 连接文件。类似于 Windows 系统下面的快捷方式。

  4. 设备与设备文件。与系统外设及存储等相关的一些文件,通常都集中在 /dev 这个目录。通常又分为两种:

    • 块设备文件:就是一些存储数据,以提供系统随机访问的接口设备,例如硬盘、软盘等。
    • 字符设备文件:也即是一些串行端口的接口设备,例如键盘、鼠标等。
  5. 套接字。用来在网络上的数据连接。

  6. 管道。FIFO 是一种特殊的文件类型,它主要的目的在解决多个程序同时访问一个文件所造成的错误问题。

文件路径的变量:$PATH

当我们在执行一个命令的时候(比如说 ls),系统会依照 PATH 的设置去每个 PATH 定义的目录下查询文件名为 ls 的可执行文件,如果 PATH 定义的目录中含有多个文件名为 ls 的可执行文件,那么先查询到的同名命令先被执行。
可以使用命令

echo $PATH

查看环境变量 PATH。

shell

bash shell

shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 即是一种命令语言,又是一种程序设计语言。Shell 是指一种程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。bash shell 是 Linux 默认的 shell,它有以下几个优点:

  1. 命令记忆能力。只要在命令行中按上下键就可以找到前/后一个输入的命令。
  2. 命令与文件补全功能(使用 Tab 键)。
  3. 命令别名设置功能(alias)。
  4. 作业控制、前台、后台控制。
  5. 程序脚本(shell script)。

变量的显示与设置

echo 命令打印变量:

echo $变量名 /echo ${变量名}

使用等号给变量赋值:

变量名=变量值

如果该变量需要在其他子进程执行,则需要以 export 来使变量变成环境变量:

export 变量名

unset 命令取消变量:

unset 变量名

env 命令可以查看环境变量:

env

set 命令可以查看 bash 内的全部变量:

set

“$” 本身也是一个变量。这个代表的是目前这个 Shell 的线程代号,即所谓的 PID 。可以使用命令查询 PID:

echo $$

“?” 也是特殊的变量。在 bash 里面这个变量很重要。这个变量是上一个执行的命令所回传的值。当我们执行某些命令时,这些命令都会回传一个执行后的代码。一般来说,如果成功执行命令,则会回传一个 0 值。

环境变量和自定义变量

env 可以查看环境变量,set 可以查看环境变量和自定义变量。环境变量和自定义变量的区别就在于该变量是否会被子进程所继续引用。
当你登录 Linux 并取得一个 bash 后,你的 bash 就是一个独立的进程。接下来你在 bash 下面所执行的任何命令都是由这个 bash 所衍生出来的,那些被执行的命令就被称为子进程。而子进程只会继承父进程的环境变量,而不会继承父进程的自定义变量。

变量键盘读取、数组与声明

read 命令可以输入变量,执行 read 命令后,系统会等待你从键盘读入变量值:

read 变量名

declare 可以声明变量类型:

declare [-aixr] 变量名

其中 [-aixr] 参数有以下几种:

  1. -a:将变量定义为数组类型。
  2. -i:将变量定义为整数数字。
  3. -x:将变量设置成环境变量。
  4. -r:将变量设置为 readonly 类型,该变量不可被更改内容,也不能重设。

命令别名设置

alitas 可以给命令设置别名:

alitas 别名=‘命令’

unalitas 可以取消别名:

unalitas 别名 

终端环境的设置

使用命令 stty 可以查看终端机输入按键的含义:

pwnki@LAPTOP-KETPO6R7:/mnt/c/Users/86189$ stty -a
speed 38400 baud; rows 30; columns 120; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q;
stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

常见的有以下几种:

  1. eof:End of life 的意思,代表结束输入;
  2. erase: 向后删除一个字符;
  3. intr: 送出一个 interrupt 的信号给目前正在运行的程序;
  4. kill:删除在目前命令行上的所有文字;
  5. quit:送出一个 quit 的信号给正在运行的进程;
  6. start: 在某个进程停止后。重新启动它的输出;
  7. stop:停止目前屏幕的输出;
  8. susp:送出一个 terminal stop 的信号给正在运行的进程;

通配符与特殊符号

常用的通配符有:

  • *:代表 0 到无穷多个任意字符。
  • ?:代表一定有一个任意的字符。
  • []:同样代表一定有一个在中括号内的字符。
  • [-]:若有减号在中括号内时,代表在编码顺序内的所有字符。
  • [^]:若中括号内的第一个字符为指数符号(^),那代表反向选择。

常用特殊符号:

  • #:批注符号,这个最常被使用在 script 中,视为说明。其后的数据均不执行。
  • \:转义符号,将特殊字符或者通配符还原成一般字符。
  • |:管道,分隔两个管道命令的界定。
  • ;:连续命令执行分隔符,连续性命令的界定。
  • ~:用户的主文件夹。
  • $:使用变量前导符,即是变量之前需要加的变量替代值。
  • &:作业控制,将命令变成背景下工作。
  • !:逻辑运算意义上的 “非” 的意思。
  • /:目录符号,路径分隔的符号。
  • >,>>:数据流重定向,输出导向,分别是 “替换” 与 “累加” 。
  • <,<<:数据流重定向,输入导向。
  • '':单引号,不具有变量置换的功能。
  • "":具有变量置换的功能。
  • ``:两个 “`” 中间为可以先执行的命令,也可以使用 $() 。
  • ():中间为子 shell 的起始和结束。
  • {}:在中间为命令块的组合。

命令执行的判断依据

有以下几种情况:

  1. ;:从左到右依次执行指令,指令以 “;” 为分隔。
cmd;cmd
  1. $?与 && 或 ||:如果两个命令之间具有相依性,而这个相依性主要判断的地方就在于前一个命令执行的结果是否正确。如果前一个命令的执行结果正确,在 Linux 下面会回传一个 $?=0 的值,再借助 “&&” 与 “||” 就能控制后续命令是否执行。
命令执行 说明
cmd1 && cmd2 若 cmd1 执行完毕且正确执行($?=0),则开始执行 cmd2;若 cmd1 执行完毕且为错误($?!=0),则 cmd2 不执行。
cmd1 || cmd2 若 cmd1 执行完毕且正确执行($?=0),则 cmd2 不执行;若 cmd1 执行完毕且为错误($?!=0),则开始执行 cmd2 。

管道命令

管道命令 “|” 仅能处理经由前面一个命令传来的正确信息,也就是 standard output 的信息,对于 stadandard error 并没有处理能力。
每个管道后面接的第一个数据必定是 “命令” ,而且这个命令必须要能够接收 standard input 的数据才行,这样的命令才可以是“管道命令”,例如 less,more,head,tail 等都是可以接收 standard input 的管道命令。至于 ls,cp,mv 等就不是管道命令了。因为 ls,cp,mv 并不会接收来自 stdin 的数据。也就是说:

  1. 管道仅会处理 standard output ,对于 standard error output 会予以忽略。
  2. 管道命令必须要能够接收来自前一个命令的数据称为 standard input 继续处理才行。

shell script

shell script 是利用 shell 功能所写的一个程序,这个程序是使用纯文本文件,将一些 shell 语法与命令(含外部命令)写在里面,搭配正则表达式、管道命令与数据流重定向等功能,以达到我们所想要的处理目的。编写 shell scrpit 有以下注意事项:

  1. 命令的执行是从上而下的、从左而右地分析与执行;
  2. 命令、参数间的多个空白会被忽略掉;
  3. 空白行也将被忽略掉,并且 tab 按键所得的空白同样视为空格键。
  4. 如果读取到一个 Enter 符号,就尝试开始执行该行命令;
  5. 可以使用 “[Enter]” 来扩展至下一行;
  6. “#” 可以作为批注。

编写第一个 script

程序 “Hello World”

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Hello Wrold! \a \n"
exit 0

程序由以下几部分组成:

  1. 第一行 “#!/bin/bash” 声明这个 script 使用的 shell 名称。
  2. 可以使用 “#” 写上有关程序的注释。
  3. 主要环境变量声明。
  4. 主要程序部分。
  5. 告知执行结果。

script 的执行方式区别

不同的 script 执行方式会造成不一样的结果。尤其是对 bash 的环境影响很大。

  1. 利用直接执行的方式来执行 scrpit。 scrpit 会使用一个新的 bash 环境来执行脚本内的命令。也就是说,使用这种执行方式时,其实 scrpit 是在子进程的 bash 内执行的。这个问题的重点在于,子进程内的各项变量或操作将会结束而不会传回到父进程中。
  2. 利用 source 命令执行脚本。source 命令会在当前进程中执行脚本,这样各项操作都会在当前的 bash 内生效。

善用判断式

比如:

test -e /dmtsai && echo "exist" || echo "Not exist"

最后结果就能告诉我们是 “exist” 还是 “Not exist”。

善用判断符号

我们可以利用判断符号 “[]” 来进行数据的判断,比如想要知道 $HOME 这个变量是否为空,可以这样写:

[-z "$HOME" ] ; echo $?

条件判断式

格式为:

if[条件判断式]; then
      当条件成立时,执行的命令
fi

程序 sh02.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

read -p "Please input (Y/N):"  yn

if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then
    echo "OK, continue"
    exit 0
fi

if [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
    echo "Oh ,interrupt!"
    exit 0
fi
echo "I don't know what your choice is" && exit 0

利用 case……esac 判断

格式为:

case $变量名称 in
      "第一变量内容")
            程序段
            ;;
      "第二变量内容")
            程序段
            ;;
      *)
            不包含第一个变量内容和第二个变量内容的其他程序执行段
            exit 1
            ;;
esac

程序 sh03.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

case $1 in
    "hello")
        echo "Hello,how are you ?"
        ;;
    "")
        echo "You MUST input parameters, ex> {$0 someword}"
        ;;
    *)
        echo "Usage $0 {hello}"
        ;;
esac

利用 function

格式为:

function fname() {
      程序段
}

程序 sh04.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

function printit(){
    echo -n "Your choice is "
}

echo "This program will print your selection !"
case $1 in
    "one")
        printit; echo $1 | tr 'a-z' 'A-Z'
        ;;
    "two")
        printit; echo $1 | tr 'a-z' 'A-Z'
        ;;
    *)
        echo "Usage $0 {one|two|three}"
        ;;
esac

循环

格式为:

while [condition]
do
      程序段落
done
until [condition]
do
      程序段落
done

程序 sh05.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

while [ "$yn" != "yes" -a "$yn" != "YES" ]
do
    read -p "Please input yes/YES to stop this program: " yn
done
echo "OK! you input the correct answer."

for...do..done(固定循环)

格式:

for var in con1 con2 con3 ...
do
      程序段
done

for((初始值;限制值;执行步长))
do
      程序段
done

程序 sh06.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

for animal in dog cat elephant
do
    echo "There are ${animal}s..."
done

程序 sh07.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

read -p "Please input a number,I will count for 1+2+...+your_input: " nu

s = 0
for ((i=1; i<=$nu; i=i+1))
do
    s=$(($s+$i))
done

echo "The result of '1+2+3...+$nu' is ==> $s"

shell script 的追踪与调试

sh [-nvx] srcipts.sh

参数:

  • -n:不要执行 scrpit,仅查询语法问题;
  • -v:在执行 script 之前,先将 scrpit 内容输出到屏幕上;
  • -x:讲使用到的 script 内容显示到屏幕上;

内容来源

菜鸟教程-linux
《鸟哥的Linux私房菜》

posted @ 2021-01-08 21:41  PwnKi  阅读(228)  评论(0编辑  收藏  举报