关于 shell

linux的shell究竟有什么神奇之处。。。



https://blog.csdn.net/liuyiy/article/details/8063817

Linux登陆主机后,在执行Script之前,其实我们已经处于一个shell中,即Login shell。它是将来要执行Script的父shell。如root账号默认为/bin/bash。
     Linux下每个账号都可以自定义Login shell,在/etc/passwd文件中。Login shell定义在第七个字段,如果这个字段的shell程序不存在、不合法,或执行失败,则无法登陆主机。
     当在执行一个Shell Script时,父shell会根据Script程序的第一行#!之后指定的shell程序开启一个子shell环境,然后在子shell中执行此Shell Script,一旦执行完毕,子shell结束,回到父shell,不会影响原父shell的环境。

Linux执行Script有三种执行方式:
1.source filename 或者 . filename
  注意. Filename中,. 和filename之间有个空格。
  此命令式在当前shell环境下读取并执行filename中的命令。该filename文件可以无执行权限。通常用于重新执行刚修改的初始化文档。source命令(从 C Shell 而来)是bash shell的内置命令。 点命令,就是个点符号,(从Bourne Shell而来),就是顺序的执行文件里的命令而已。
2.sh filename 或者 bash filename
  此命令是在当前相应的bash环境下新建一个子shell读取并执行FileName中的命令,该filename文件可以无执行权限。
3.  ./filename
  此命令打开一个子shell来读取并执行filename中命令,该文件必须必须有可执行的权限。chmod +x filename。
三者的区别:
1.当shell脚本具有可执行权限时,用sh filename与./filename执行脚本是没有区别得。./filename是因为当前目录没有在PATH中,所有"."是用来表示当前目录的。
2.sh filename 重新建立一个子shell,在子shell中执行脚本里面的语句,该子shell继承父shell的环境变量,但子shell新建的、改变的变量不会被带回父shell,除非使用export。
3.source filename:这个命令其实只是简单地读取脚本里面的语句依次在当前shell里面执行,没有建立新的子shell。那么脚本里面所有新建、改变变量的语句都会保存在当前shell里面。
举例:
1.新建一个test.sh脚本,内容为:A=1。
2.然后使其可执行chmod +x test.sh。
3.运行sh test.sh后,echo $A,显示为空,因为A=1并未传回给当前shell。
4.运行./test.sh后,也是一样的效果。
5.运行source test.sh 或者 . test.sh,然后echo $A,则会显示1,说明A=1的变量在当前shell 中。
举例:
1.新建一个sh01.sh脚本,内容为
#!/bin/bash
echo $SHLVL  (输出当前shell的层次)
2.然后使其可执行chmod +x sh01.sh。
3.运行sh sh01.sh后,输出3。
4.运行./ sh01.sh后,也是一样的效果。
5.运行source sh01.sh 或者 . sh01.sh,输出2。
举例:
1.登录主机后,打开一个终端,输入echo $SHLVL,输出2。
2.输入bash,进入一个子shell,然后再输入echo $SHLVL,输出3。
3.输入exit,然后再输入echo $SHLVL,输出2。

4.输入exit,退出终端。


============

https://blog.csdn.net/a600423444/article/details/6451111

Login Shell

登录主机后,在执行Bash Script之前,其实我们已经处于一个BashShell中。

这个Shell叫login Shell,是将来我们执行任何Script的上层环境。又叫父SHell

 

其实每个帐号都可以自定义loginShell。以Linux来说,帐号的login Shell定义在/etc/passwd这个文件中。

/etc/passwd的每一行代表一个帐号,共有7个字段,之间用:隔开。

帐号:x:UID 使用者代码:GID 群组代码:用户信息:主目录:login shell路径

第二栏x为密码栏,基于系统安全考虑,编码后的密码已经被放入/etc/passwd文件中。

login Shell定义在第7个字段,如果这个字段的Shell程序不存在、不合法,或执行失败,则无法登录主机。

 

父Shell、子Shell

当在执行一个Shell Script时,父Shell会根据Script程序的第一行#!之后指定的Shell程序开启一个子Shell环境,然后在子Shell中执行此Shell Script。一旦子Shell中的Script执行完毕,此子Shell随即结束,回到父Shell中,不会影响父Shell原本的环境。

子Shell环境拥有与父Shell相同的环境变量、标准输入、输出、错误等。

 

例如:

test.sh文件内容

#!/bin/bash

cd /var/www/html

 

命令行:chmod +x /test.sh

命令行:./test.sh

执行完脚本后还原到父Shell,并且父Shell并没有进入/var/www/html目录。

注:这是因为当执行Shell文件时,父Shell会创建子Shell,各自独立。

 

如果需要使用父Shell来执行此脚本,可以使用:

命令行:. ./test.sh

注意.与./之间有一个空格符

 

 

子Shell继续开启子Shell

与父Shell启动子Shell方式一样,继续调用下去,即子Shell开启子Shell。

通过$SHLVL变量,可以知道当前所在Shell的层次

=================


当我们在一个 shell 里运行一个脚本程序时,该 shell 就会 fork 出一个新进程,从而启动了另一个命令解释器(由脚本中第一行的 #!/bin/xxx 指定,如 bash shell)来解释运行我们这个脚本。也就是说,这个新进程是一个子 shell,而之前的 shell 是个父 shell 。

在我们所运行的脚本里,我们还可以启动新的子 shell 进程,这些子 shell 进程使脚本并行地运行着多个子任务。一般而言,在一个脚本里执行一个外部命令(普通的可执行文件)时,shell 会 fork 出一个子进程,然后再用 exec 来执行这个程序;但是,bash shell 的内置命令(builtin)却不会这样,它们是直接执行的。所以,等价的内置命令的执行速度会比执行外部命令要来的快。

在一对括号 (...) 里可以放置一组指令,这些指令是在一个子 shell 里执行的。在子 shell 里的变量不能被这段子 shell 外的代码直接访问,也就是说子 shell 里的变量不能被父 shell 所存取,实际上它们是局部变量
这里可以参考:(( ))和 [[ ]] 和 shell 与 命令的执行 这两篇文章。

下面用一段代码进行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
 
echo "Subshell level = $BASH_SUBSHELL"
 
outer_variable=Outer
outer_variable2=Outer2
 
(
  echo "Subshell level INSIDE subshell = $BASH_SUBSHELL"
  inner_variable=Inner
  outer_variable2=Outer_var_changein_subshell
  echo "From Subshell,\"inner_variable\"=$inner_variable"
  echo "From parent shell,\"outer\"=$outer_variable"
  echo "From parent shell, \"outer\"=$outer_variable2"
)
 
echo "In parent shell, check \"outer_variable\" value:$outer_variable"
echo "In parent shell, check \"outer_variable2\" value:$outer_variable2"
 
echo
echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL"
echo
 
if [ -z "$inner_variable" ]
then
     echo "inner_variable undefined in main body of shell"
else
     echo "From main body of shell,\"inner_variable\"=$inner_variable"
fi
 
exit 0

运行输出:
引用
beyes@debian:~/shell$ ./subshell.sh
Subshell level = 0
Subshell level INSIDE subshell = 1
From Subshell,"inner_variable"=Inner
From parent shell,"outer"=Outer
From parent shell, "outer"=Outer_var_changein_subshell
In parent shell, check "outer_variable" value:Outer
In parent shell, check "outer_variable2" value:Outer2

Subshell level OUTSIDE subshell = 0

inner_variable undefined in main body of shell

在上面的代码中, BASH_SUBSHELL 是一个环境变量,它表示进入子 shell 的层级,比如处于当前 shell 时,该变量值为 0;当在当前 shell 派生的子 shell 里时,该变量值为 1;如果该子 shell 又派生出一个子 shell,那么该变量在此间的值就为 3,以此类推。

在代码中,( ) 里的代码段是在子 shell 里执行的,而 inner_variable 作为局部变量,它的值可以在 ( ) 这段代码里 echo 出来,但是一旦返回到父shell 时,它就是未定义的,所以会输出“ inner_variable undefined in main body of shell”。也就是说,局部变量不能被外部代码所访问。

从输出可以看到,在子 shell 中和父 shell 中变量 outer_variable 的输出值是一样的;相对应的 outer_variable2 变量即使在子 shell 中进行了修改,但是当返回到父 shell 对其输出时,它却还是父 shell 中原来所赋的值。从这里可以看出,子 shell 可以 “感知” 父 shell 中的变量,但它不能修改它。其本质的原因和 fork() 函数的原理有关。在 UNIX/LINUX 中,fork 出来的子进程实际上是对父进程的一种拷贝,而子 shell 就是父shell fork 出来的一个子进程,所以它理所当然的有了父shell 中的一片拷贝。所以,子 shell 里的 outer_variable 和 outer_variable2 变量虽然和父 shell 的同名,但它们并不是同一个变量,而是父 shell 里的一个副本。

说到父shell 和 子 shell,那么会想到 export 这个命令。export 也是 bash 的一个内置命令。它主要是用来将父 shell 里的变量导出供子 shell 使用。它有如下特征:
1. 用 export 导出的变量放在“导出变量列表”中,它可以被子 shell (子 shell 的子 shell 也是如此)拷贝并使用。
2. 被 export 出来的变量虽然可以被子 shell 使用,但它也只是一个拷贝,而不会影响到父 shell 中的值以及其它子 shell 中的值。

看下面示例;

1. 先在当前 shell 里 export 一个变量:
引用
beyes@debian:~/shell$ export exp8temp="hello world"
beyes@debian:~/shell$ echo $exp8temp
hello world


2. 运行一个脚本 echo 此变量(该脚本只有一句话即 echo $exp8temp ):
引用
$ ./exp8.sh 
hello world

由上可见,父 shell 里 export 的变量可以被子 shell 读取。

3. 测试一下子 shell 更改此变量是否会影响父 shell 里的值,子 shell 代码如下:
1
2
3
4
5
#!/bin/bash
 
exp8temp= "hello shell"
 
echo $exp8temp

检验上面的情景:
引用
beyes@debian:~/shell$ ./exp8.sh 
hello shell
beyes@debian:~/shell$ echo $exp8temp
hello world

可见子 shell 对父 shell 里 export 出来的变量进行修改并不能影响到父 shell。这说明了,子 shell 只是在“导出变量列表“里对该变量进行了一个拷贝。但反过来,父shell再次更改此变量时,子 shell 再去读时,读到的是新值,而不是原来的值。

4. 如果在子 shell 里 export 出的变量,父 shell 是否能读到呢?
先将下面一段代码放在后台运行:
1
2
3
4
5
6
7
#!/bin/bash
 
export exp9temp= "hello world"
 
sleep 30
 
exit 0

然后在在 30 秒内在父 shell 里读取一下 $exp9temp 的值,发现输出为空。所以我们得出结论,export 出来的变量不能导出到父进程或者是父进程的环境里。一个自己称可以继承父进程的东西,而不能反过来去影响父进程。

那么子 shell 有什么办法可以向父 shell 传递自己的变量吗?下面方法可以考虑:

1. 通过一个中间文件进行
1
2
3
4
5
6
7
8
9
10
#!/bin/bash
 
(
  subvar= "hello shell"
  echo "$subvar" > temp.txt
)
 
read pvar < temp.txt
 
echo $pvar

运行输出:
引用
$ sh subandp.sh 
hello shell


2. 通过命令替换
引用
#!/bin/bash

pvar=`subvar="hello shell";echo $subvar`

echo $pvar

运行输出:
引用
$ ./subandp.sh 
hello shell

执行命令替换符(两个反单引号)之间的命令也是在子 shell 来完成的。

3. 使用命名管道
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
 
mkfifo -m 777 npipe
 
(
   subsend= "hello world"
   echo "$subsend" > npipe &
  )
 
read pread < npipe
 
echo "$pread"
 
exit 0

运行输出:
引用
beyes@debian:~/shell$ ./var.sh 
hello world

关于有名管道创建命令 mkfifo 可参考: http://www.groad.net/bbs/read.php?tid-3707.html

4. 使用 here 文档
1
2
3
4
5
6
7
8
#!/bin/bash
 
read pvar << HERE
`subvar= "hello shell"
echo $subvar`
HERE
 
echo $pvar

运行输出:
引用
$ ./subandp.sh 
hello shell


方法应该还有很多,这些方法的本质原理基于进程间的通信。




============

https://www.jianshu.com/p/7db79d7997b5

子shell

运行一个shell脚本时会启动另一个命令解释器. 就好像你的命令是在命令行提示下被解释的一样, 类似于批处理文件里的一系列命令.每个shell脚本有效地运行在父shell(parent shell)的一个子进程里.这个父shell是指在一个控制终端或在一个xterm窗口中给你命令指示符的进程.

shell脚本也能启动他自已的子进程. 这些子shell(即子进程)使脚本并行地,有效率地地同时运行多个子任务.

圆括号运行子shell

嵌在圆括号里的一列命令在一个子shell里运行。

例如:

(
echo abcd
echo cdef
)

输出为:

abcd
cdef

在子shell里的变量不能被这段子shell代码块之外外面的脚本访问.这些变量是不能被产生这个子shell的父进程(parent process)存取的,实际上它们是局部变量(local variables).

例如:

(a=b)
echo $a

输出为空

在子shell中的目录更改不会影响到父shell.

子shell可用于为一组命令设定临时的环境变量

进程在不同的子shell中可以并行地执行.这样就允许把一个复杂的任务分成几个小的子问题来同时地处理。

管道产生子shell

管道(|)也会产生子shell。在子shell中可以读取父shell中的变量,但是不能写这些变量。有时我们可以通过重定向输入输出的方式来传递这些变量。详细的可以参考I/O重定向



作者:Fengya
链接:https://www.jianshu.com/p/7db79d7997b5
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
===============


https://blog.csdn.net/chenguolinblog/article/details/12870587

 Linux是一种用户控制的多作业操作系统,系统允许多个系统用户同时提交作业,而一个系统用户又可能用多个Shell登录,每个系统用户可以用一个Shell提交多个作业

 

 1 子Shell

    1 父子Shell是相对的,它描述了两个Shell进程的fork关系,父Shell指在控制终端或窗口给出提示符的进程,子Shell是由父Shell创建的进程,在Linux中,只有一个函数可以创建子进程,那就是fork函数

    

    2 圆括号结构能够强制将其中的命令运行在子Shell中,它的基本格式为

       (command1 command2 command....n)

       上述结构表示圆括号内的n条命令在子Shell中运行

  

    3 子Shell能够从父Shell继承得来的属性如下

       1 当前工作目录

       2 环境变量

       3 标准输入,标准输出和标准错误输出

       4 忽略的信号

       5 除了环境变量和.bashrc文件中定义变量之外的Shell变量

       6 未被忽略的信号处理


 2 进程处理

    1 进程和作业是有区别的,一个正在执行的进程称为作业,一个作业可以包含多个进程。用户提交作业到操作系统,作业的完成可能依赖于启动多个进程。因此简单的说,作业是用户层面的概念,而进程是操作系统层面的概念

    

    2 进程是针对整个Linux系统而言的,作业是针对Shell而言的。作业有两种运行方式,前台运行和后台运行

    

    3 前台运行的作业指能够控制当前终端或窗口,且能接收用户的输入;而后台的运行的作业则不在当前激活的终端或窗口中运行,是在用户看不见的情况下运行的

 

    4 Shell中内置命令fg能够把后台的作业放到前台运行,如果没有带参数的fg命令就是将最近提交的那个后台作业放置到前台运行


    5 指定作业的方法及其意义

          参数                 意义

           %n            n为后台作业的作业号

           %string     命令以string字符串开始的后台作业

           %?string   命令包含string字符串的后台作业

           %+或%%  最近提交的后台作业

           %-             最近第二个提交的后台作业


    6 Shell内置的命令jobs是用于显示所有后台运行的作业

    

 3 信号
    1 向进程发送信号大多通过"Crtl"键加上一些功能键来实现的

    

    2 Ctrl组合键,信号类型及其意义

        组合键               信号类型                                                意义

        Ctrl+C        INT信号,即interupt信号                   停止当前运行的作业

        Ctrl+Z        TSTP信号,即terminal stop信号        使当前运行的作业暂时停止(转入阻塞态)

        Ctrl+\         QUIT信号                                           Ctrl+C的强化版本,当Ctrl+C无法停止作业时,使用此组合键

        Ctrl+Y        TSTP信号,即terminal stop信号       当进程从终端读取输入数据时,暂时停止该进程

====================
https://cnbin.github.io/blog/2015/06/23/fu-shell-yu-zi-shell/

父 Shell 与子 Shell

Jun 23rd, 2015 3:04 pm

Login Shell

登录主机后,在执行 Bash Script 之前,其实我们已经处于一个 BashShell 中。

这个 Shelllogin Shell,是将来我们执行任何 Script 的上层环境。又叫 父SHell

其实每个帐号都可以自定义 loginShell。以 Linux 来说,帐号的 login Shell 定义在 /etc/passwd 这个文件中。

/etc/passwd 的每一行代表一个帐号,共有7个字段,之间用 隔开。

帐号:x:UID 使用者代码:GID 群组代码:用户信息:主目录:login shell路径

第二栏 x为密码栏,基于系统安全考虑,编码后的密码已经被放入 /etc/passwd 文件中。

login Shell 定义在第7个字段,如果这个字段的 Shell 程序不存在、不合法,或执行失败,则无法登录主机。

父 Shell、子 Shell

当在执行一个 Shell Script 时,父Shell 会根据 Script 程序的第一行 #! 之后指定的 Shell 程序开启一个 子Shell 环境,然后在子Shell 中执行此 Shell Script。一旦 子Shell 中的 Script 执行完毕,此 子Shell 随即结束,回到 父Shell 中,不会影响 父Shell 原本的环境。

子Shell环境拥有与 父Shell 相同的环境变量、标准输入、输出、错误等。

例如:

test.sh文件内容
#!/bin/bash
cd /var/www/html

命令行:

chmod +x /test.sh

命令行:

./test.sh

执行完脚本后还原到 父Shell,并且 父Shell 并没有进入 /var/www/html目录

注:这是因为当执行 Shell 文件时,父Shell 会创建 子Shell,各自独立。

如果需要使用 父Shell 来执行此脚本,可以使用:

命令行:

. ./test.sh

注意 ../ 之间有一个空格符

子 Shell 继续开启子 Shell

父Shell 启动 子Shell 方式一样,继续调用下去,即 子Shell 开启 子Shell

子 Shell 能够从 父Shell 继承得来的属性如下:

  • 当前工作目录
  • 环境变量
  • 标准输入、标准输出和标准错误输出
  • 所有已打开的文件标识符

子 Shell 不能从父 Shell 继承得来的属性,归纳如下:

除了环境变量和 .bashrc 文件中定义变量之外的 Shell 变量

圆括号结构

圆括号结构能够强制将其中的命令运行在 子Shell 中,它的基本格式为:

(
command 1
command 2
…
command n
)

圆括号内的 n 条命令在 子Shell 中运行,bash 版本3之后定义了内部变量 BASH_SUBSHELL,该变量记录了 子Shell 的层次。

子Shell 只能继承 父Shell 的一些属性,但是,子Shell 不可能反过来改变 父Shell 的属性。



------------------------------------------------

http://wiki.jikexueyuan.com/project/linux-command/chap37.html











































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shell脚本面试题是与Linux Shell相关的问题,以下是几个常见的面试题及其解答: 1. 什么是Shell脚本? Shell脚本是一种用于自动化执行任务的脚本语言。它可以通过编写命令和脚本来实现自动执行各种任务,包括文件操作、系统管理和软件安装等。 2. Shell脚本的文件扩展名是什么? Shell脚本的文件扩展名通常是.sh。 3. 如何指定一个脚本要使用的Shell类型? 可以使用shebang(井号加叹号)来指定脚本要使用的Shell类型。例如,#!/bin/bash表示脚本使用Bash Shell。 4. 如何将一个Shell脚本变成可执行文件? 可以使用chmod命令将Shell脚本文件设置为可执行文件。例如,使用chmod +x script.sh命令将script.sh文件设置为可执行文件。 5. 如何在Shell脚本中获取命令行参数? 可以使用特殊变量$1、$2、$3等来获取命令行参数。$1表示第一个参数,$2表示第二个参数,依此类推。 6. 如何在Shell脚本中进行条件判断? 可以使用if语句进行条件判断。例如: ``` if [ 条件 ]; then # 如果条件成立执行的代码 else # 如果条件不成立执行的代码 fi ``` 7. 如何在Shell脚本中进行循环操作? 可以使用for循环或while循环进行循环操作。例如: ``` # for循环 for 变量 in 列表; do # 循环体 done # while循环 while 条件; do # 循环体 done ``` 8. 如何在Shell脚本中读取文件内容? 可以使用while循环结合read命令来逐行读取文件内容。例如: ``` while read line; do # 处理每行内容的代码 done < 文件名 ``` 9. 如何定义和使用Shell脚本中的函数? 可以使用function关键字定义函数,然后通过函数名调用函数。例如: ``` function 函数名 { # 函数体 } # 调用函数 函数名 ``` 10. 如何在Shell脚本中进行字符串操作? 可以使用字符串操作符来进行字符串的拼接、替换等操作。例如: ``` # 字符串拼接 str="Hello" str2="World" result=$str$str2 # 字符串替换 str="Hello World" result=${str/World/John} ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值