zoukankan      html  css  js  c++  java
  • shell相关知识1

    转自https://www.cnblogs.com/ting152/p/12554480.html

     

     

    1.组命令

    组命令,就是将多个命令划分为一组,或者看成一个整体。

    用法区别

    Shell 组命令的写法有两种:

    { command1; command2;. . .;  }
    (command1; command2;. . . )

    1. 由花括号{}包围起来的组命名在当前 Shell 进程中执行,而由小括号()包围起来的组命令会创建一个子 Shell,所有命令都在子 Shell 中执行。
    2. 使用花括号{}时,花括号与命令之间必须要有一个空格,并且最后一个命令必须用一个分号或一个换行符结束
    3. 组命令可以将多条命令的输出结果合并在一起,在使用重定向和管道时会特别方便。

    两种写法的重要不同:{}包围的组命令在当前 Shell 进程中执行,由()包围的组命令会创建一个子Shell,所有命令都会在这个子 Shell 中执行
    在子 Shell 中执行意味着,运行环境被复制给了一个新的 shell 进程,当这个子 Shell 退出时,新的进程也会被销毁,环境副本也会消失,所以在子 Shell 环境中的任何更改都会消失(包括给变量赋值)。因此,在大多数情况下,除非脚本要求一个子 Shell,否则使用{}比使用()更受欢迎,并且{}的进行速度更快,占用的内存更少

    举栗 
    将多条命令的输出重定向到out.txt文件

    1.普通模式

    1. ls -l > out.txt #>表示覆盖
    2. echo "test432" >> out.txt #>>表示追加
    3. cat test.txt >> out.txt

    2.使用组命令

    { ls -l ;echo "test432";cat test.txt; }>out.txt

    (ls -l ;echo "test432";cat test.txt)>out.txt

    组命令与管道结合

    (ls -l ;echo "test432";cat ../test.txt)|wc -l

    2.子进程

    2.1 什么是子进程

    子进程的概念是由父进程的概念引申而来的。在 Linux 系统中,系统运行的应用程序几乎都是从 init(pid为 1 的进程)进程派生而来的,所有这些应用程序都可以视为 init 进程的子进程,而 init 则为它们的父进程。

    Shell 脚本是从上至下、从左至右依次执行的,即执行完一个命令之后再执行下一个。如果在 Shell 脚本中遇到子脚本(即脚本嵌套,但是必须以新进程的方式运行)或者外部命令,就会向系统内核申请创建一个新的进程,以便在该进程中执行子脚本或者外部命令,这个新的进程就是子进程。子进程执行完毕后才能回到父进程,才能继续执行父脚本中后续的命令及语句。

    使用pstree -p命令就可以看到 init 及系统中其他进程的进程树信息(包括 pid):

    systemd(1)─┬─ModemManager(796)─┬─{ModemManager}(821)
                │                     └─{ModemManager}(882)
                ├─NetworkManager(975)─┬─{NetworkManager}(1061)
                │                       └─{NetworkManager}(1077)
                ├─abrt-watch-log(774)
                ├─abrt-watch-log(776)
                ├─abrtd(773)
                ├─accounts-daemon(806)─┬─{accounts-daemon}(839)
                │                        └─{accounts-daemon}(883)
                ├─alsactl(768)
                ├─at-spi-bus-laun(1954)─┬─dbus-daemon(1958)───{dbus-daemon}(1960)
                │                         ├─{at-spi-bus-laun}(1955)
                │                         ├─{at-spi-bus-laun}(1957)
                │                         └─{at-spi-bus-laun}(1959)
                ├─at-spi2-registr(1962)───{at-spi2-registr}(1965)
                ├─atd(842)
                ├─auditd(739)─┬─audispd(753)─┬─sedispatch(757)
                │               │                └─{audispd}(759)
                │               └─{auditd}(752)

    2.2 创建子进程

    创建子进程的方式说明 
    • 第一种只使用 fork() 函数,子进程和父进程几乎是一模一样的,父进程中的函数、变量(全局变量、局部变量)、文件描述符、别名等在子进程中仍然有效。我们将这种子进程称为子 Shell(sub shell)
    1. 使用 fork() 函数创建一个子进程相当于对父进程进行了克隆,除了 PID(进程ID)等极少的参数不同外,子进程的一切都来自父进程,包括代码、数据、堆栈、打开的文件等,就连代码的执行位置(状态)都是一样的。
    2. 但是,后期随着各自的发展轨迹不同,两者会变得不一样,但是在 fork() 出来的那一刻,两者都是一样的。
    组命令、命令替换、管道
    • 第二种使用 fork() 和 exec() 函数,即使用 fork()创建子进程后立即调用 exec() 函数加载新的可执行文件,而不使用从父进程继承来的一切,子进程和父进程之间除了硬生生地维持一种“父子关系”外,再也没有任何联系了,它们就是两个完全不同的程序。

    举栗:
    在 ~/bin 目录下有两个可执行文件分别叫 a.out 和 b.out。现在运行 a.out,就会产生一个进程,比如叫做 A。在进程 A 中我又调用 fork() 函数创建了一个进程 B,那么 B 就是 A 的子进程,此时它们是一模一样的。但是,我调用 fork() 后立即又调用 exec() 去加载 b.out,这可就坏事了,B 进程中的一切(包括代码、数据、堆栈等)都会被销毁,然后再根据 b.out 重建建立一切。这样一折腾,B 进程除了 ID 没有变,其它的都变了,再也没有属于 A 的东西了。

    1. 以新进程的方式运行脚本文件,比如bash ./test.sh; chmod +x ./test.sh; ./test.sh
    2. 在当前 Shell 中使用 bash 命令启动新的 Shell

    2.3 子进程总结

    子 Shell 虽然能使用父 Shell 的的一切,但是如果子 Shell 对数据做了修改,比如修改了全局变量,这种修改也只能停留在子 Shell,无法传递给父 Shell。不管是子进程还是子 Shell,都是“传子不传父”。

    子 Shell 才是真正继承了父进程的一切,这才像“一个模子刻出来的”;普通子进程和父进程是完全不同的两个程序,只是维持着父子关系而已。

    3.如何检测子shell与子进程

    echo $$输出当前进程ID,echo $PPID输出父shell ID

     

    命令

    结果

    结论

    输出当前进程与父进程ID

    echo $$;echo $PPID

    34451

    34450

     

    子进程形式输出进程ID

    子进程

    bash

    echo $$;echo $PPID

    exit

    52886

    34451

    在普通的子进程中,$ 被展开为子进程的 ID

    组命令形式输出进程ID

    子shell

    (echo $$;echo $PPID)

    34451

    34450

    子shell和父shell中的ID是一样的

    这是因为$ 变量在子 Shell 中无效!Base 官方文档说,在普通的子进程中,$ 确实被展开为子进程的 ID;但是在子 Shell 中,$ 却被展开成父进程的 ID

    管道形式输出进程ID

    子shell

    echo "test" | { echo $$;echo $PPID; }

    34451

    34450

    进程替换形式输出进程ID

    read < <(echo $$ $PPID)

    $ echo $REPLY

    34451 34450

  • 相关阅读:
    hdu 4710 Balls Rearrangement()
    hdu 4707 Pet(DFS水过)
    hdu 4706 Children's Day(模拟)
    hdu 4712 Hamming Distance(随机函数暴力)
    csu 1305 Substring (后缀数组)
    csu 1306 Manor(优先队列)
    csu 1312 榜单(模拟题)
    csu 1303 Decimal (数论题)
    网络爬虫
    Python处理微信利器——itchat
  • 原文地址:https://www.cnblogs.com/saolv/p/13197549.html
Copyright © 2011-2022 走看看