关于read命令的两个问题

sh/bash/dash/ksh/zsh等Shell脚本
头像
nonigh
帖子: 32
注册时间: 2010-04-21 10:28

关于read命令的两个问题

#1

帖子 nonigh » 2011-12-03 14:23

1.假设家目录下有一文件file
在家目录下执行read x;cat $x
输入~/file 就会报错:cat: ~/file: 没有那个文件或目录
而./file则没有问题 这是什么原因?

2.执行echo 'a b'|read x y;echo $x $y 反回值为空
而这样就没有问题echo 'a b'|while read x y;do echo $x $y;done
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: 关于read命令的两个问题

#2

帖子 fnan » 2011-12-03 20:25

1
用eval实现波浪号扩展。
2
echo 'a b'|(read x y;echo "shell-level=$BASH_SUBSHELL x=$x y=$y");echo "shell-level=$BASH_SUBSHELL x=$x y=$y"
shell-level=1 x=a y=b
shell-level=0 x= y=
上次由 fnan 在 2011-12-04 18:21,总共编辑 1 次。
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
头像
nonigh
帖子: 32
注册时间: 2010-04-21 10:28

Re: 关于read命令的两个问题

#3

帖子 nonigh » 2011-12-04 12:03

谢谢fnan
第1个明白了
第2个还是不明白
为什么read会fork出子进程?
type -a read 显示这是一个内嵌命令啊
头像
nonigh
帖子: 32
注册时间: 2010-04-21 10:28

Re: 关于read命令的两个问题

#4

帖子 nonigh » 2011-12-04 13:57

明白了 管道符两边的命令都是在子进程中执行
但是echo $BASH_SUBSHELL|cat 得到0 好像左管道左边不是在子进程中执行的吧
另外我shell中执行:bash 这时的shell应该是子shell 但是echo $BASH_SUBSHELL还是得到0
我在脚本里写一行 echo $BASH_SUBSHELL sh执行这个脚本 也得到0
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: 关于read命令的两个问题

#5

帖子 fnan » 2011-12-04 18:55

nonigh 写了:明白了 管道符两边的命令都是在子进程中执行
但是echo $BASH_SUBSHELL|cat 得到0 好像左管道左边不是在子进程中执行的吧
另外我shell中执行:bash 这时的shell应该是子shell 但是echo $BASH_SUBSHELL还是得到0
我在脚本里写一行 echo $BASH_SUBSHELL sh执行这个脚本 也得到0
# 这个层次是相对的,不是绝对的,bash本身就不是绝对第一层,是以第一个启动的程序为相对第一层。
kose3@kose3-laptop:~$ ps -ef|grep bash
kose3 2206 2204 0 05:43 pts/0 00:00:00 bash #bash的父进程是2204.
kose3 2292 2206 0 05:54 pts/0 00:00:00 grep --color=auto bash
但是echo $BASH_SUBSHELL|cat 得到0 好像左管道左边不是在子进程中执行的吧
# 管道的左边不是子进程环境,比如:
kose3@kose3-laptop:~$ cat <<<$BASH_SUBSHELL #不是子进程环境,但cat是子进程,因为不是内建命令。
0
kose3@kose3-laptop:~$ echo $BASH_SUBSHELL #没有子进程。
0
kose3@kose3-laptop:~$
#单是这样好像还是不清楚:
kose3@kose3-laptop:~$ echo|cat <<<$BASH_SUBSHELL #管道右边也不是子进程环境。
0
#具体看看read的情况:
先打开两个终端: 1 2
1:
kose3@kose3-laptop:~$ echo $$
1743
2:
ose3@kose3-laptop:~$ ps -ef|grep bash
kose3 1743 1716 0 06:36 pts/1 00:00:00 bash #1是1743 父进程1716
kose3 1867 1716 0 07:03 pts/0 00:00:00 bash #2是1867 父进程1716
kose3 2135 1867 0 07:15 pts/0 00:00:00 grep --color=auto bash
kose3@kose3-laptop:~$
1输入命令:
kose3@kose3-laptop:~$ x=1;read x|echo 1-x=$x;echo 2-x=$x
1-x=1
(光标等待输入)
2输入命令:
kose3@kose3-laptop:~$ ps -ef|grep bash
kose3 1743 1716 0 06:36 pts/1 00:00:00 bash
kose3 1867 1716 0 07:03 pts/0 00:00:00 bash
kose3 2148 1743 0 07:19 pts/1 00:00:00 bash #read是内建命令,但在bash子进程2148执行,父进程是终端1 --1743。
kose3 2153 1867 0 07:20 pts/0 00:00:00 grep --color=auto bash
kose3@kose3-laptop:~$
1输入数字2:
kose3@kose3-laptop:~$ x=1;read x|echo 1-x=$x;echo 2-x=$x
1-x=1
2
2-x=1 #x还是=1
2输入命令:
kose3@kose3-laptop:~$ ps -ef|grep bash
kose3 1743 1716 0 06:36 pts/1 00:00:00 bash
kose3 1867 1716 0 07:03 pts/0 00:00:00 bash
kose3 2158 1867 0 07:24 pts/0 00:00:00 grep --color=auto bash #read打开的bash子进程结束了。
kose3@kose3-laptop:~$
1输入命令:
kose3@kose3-laptop:~$ x=1;read x;echo 1-x=$x;echo 2-x=$x
(光标等待输入)
2输入命令:
kose3@kose3-laptop:~$ ps -ef|grep bash
kose3 1743 1716 0 06:36 pts/1 00:00:00 bash
kose3 1867 1716 0 07:03 pts/0 00:00:00 bash
kose3 2162 1867 0 07:27 pts/0 00:00:00 grep --color=auto bash #这次read没有引起bash子进程。
kose3@kose3-laptop:~$
#后面的结果可以猜到了。
#分析一下可得出,当read和管道在一起,由于read不产生输出,shell就用子bash执行,为了马上执行后面的命令。
上次由 fnan 在 2011-12-04 20:38,总共编辑 2 次。
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
头像
nonigh
帖子: 32
注册时间: 2010-04-21 10:28

Re: 关于read命令的两个问题

#6

帖子 nonigh » 2011-12-04 20:29

#第一个管道的左边不是子进程环境,比如:
kose3@kose3-laptop:~$ cat <<<$BASH_SUBSHELL #不是子进程环境,但cat是子进程,因为不是内建命令。
0
kose3@kose3-laptop:~$ echo $BASH_SUBSHELL #没有子进程。
0
kose3@kose3-laptop:~$
cat <<$BASH_SUBSHELL #我理解的是在当前shell下fork出一个子shell cat子shell中的$BASH_SUBSHELL cat是子进程 为什么执行环境不是子进程环境?
头像
cuihao
帖子: 4793
注册时间: 2008-07-24 11:33
来自: 郑州
联系:

Re: 关于read命令的两个问题

#7

帖子 cuihao » 2011-12-04 20:34

严重仇恨LZ的头像。
求人不如求它仨: 天蓝的Wiki 屎黄的Wiki 绿
Site: CUIHAO.TK    Twitter: @cuihaoleo
Machine: Athlon64 X2 5200+ / 2x2GB DDR2-800 / GeForce GTS 450
AD: ~まだ見ぬ誰かの笑顔のために~
头像
nonigh
帖子: 32
注册时间: 2010-04-21 10:28

Re: 关于read命令的两个问题

#8

帖子 nonigh » 2011-12-04 20:40

cuihao 写了:严重仇恨LZ的头像。
不仇恨我就好...说点有用的行不 我头晕中
头像
nonigh
帖子: 32
注册时间: 2010-04-21 10:28

Re: 关于read命令的两个问题

#9

帖子 nonigh » 2011-12-04 20:47

谢谢fnan..我是新手 容我三思 可能会很久...您先休息 :em06
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: 关于read命令的两个问题

#10

帖子 fnan » 2011-12-04 21:00

nonigh 写了:
#第一个管道的左边不是子进程环境,比如:
kose3@kose3-laptop:~$ cat <<<$BASH_SUBSHELL #不是子进程环境,但cat是子进程,因为不是内建命令。
0
kose3@kose3-laptop:~$ echo $BASH_SUBSHELL #没有子进程。
0
kose3@kose3-laptop:~$
cat <<$BASH_SUBSHELL #我理解的是在当前shell下fork出一个子shell cat子shell中的$BASH_SUBSHELL cat是子进程 为什么执行环境不是子进程环境?
#1输入 cat </dev/zero
(cat 不停的输出)
2输入:
kose3@kose3-laptop:~$ ps -ef|grep -E '\bcat\b'
kose3 2255 1743 1 07:52 pts/1 00:00:00 cat #有了个cat子进程。父进程是1743.
kose3@kose3-laptop:~$ ps -ef|grep bash
kose3 1743 1716 0 06:36 pts/1 00:00:00 bash
kose3 1867 1716 0 07:03 pts/0 00:00:00 bash
kose3 2259 1867 0 07:52 pts/0 00:00:00 grep --color=auto bash #没有bash子进程,进程环境还是第一层的1743.
kose3@kose3-laptop:~$
#先看这个搞清楚进程与进程环境的关系。
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: 关于read命令的两个问题

#11

帖子 fnan » 2011-12-05 8:51

一直流行管道后面是子进程的说法,自己总有些疑惑,实际上要看是什么命令,不仅是read,只要是管道前或后的赋值操作,都由子bash进程执行,(只有子bash进程才会产生子进程环境)为何作者这样设计,不明白有什么好处。
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
头像
nonigh
帖子: 32
注册时间: 2010-04-21 10:28

Re: 关于read命令的两个问题

#12

帖子 nonigh » 2011-12-06 16:59

我已经完全晕了 研究了两天 牵扯的东西越来越多 我都不知道从何谈起了 :em20

关于进程环境 我好像是明白了 不知道是不是这样理解:
执行外部命令时有个fork-exec的步骤 经过exec函数处理后 代替了fork出的子shell 所以进程环境还是之前父shell的

关于执行bash和sh运行脚本后 $BASH_SUBSHELL值仍然为0 我是按以下来理解的 不知道对不对:
fork出来的子shell $BASH_SUBSHELL的值会+1
执行bash后和用sh运行脚本时 fork出了子shell 这个子shell里的$BASH_SUBSHELL也会+1 但是随后会触发exec exec调用了bash代替了这个子shell
这个bash是初始的 所以$BASH_SUBSHELL的值又回到了默认的0

另外还有一些疑问...
1.
前面您提到的例子:cat </dev/zero 创建了一个子进程 进程环境是父shell的
如果这样:(cat </dev/zero)呢?
我理解的是括号()fork了一个子shell 这个子shell中的cat是外部命令 所以应该再fork一个shell 称为孙shell吧 然后exec函数执行cat代替了这个孙shell
但是ps查看进程发现 cat这个进程的父shell还是最开始的运行(cat </dev/zero)的那个shell 它们之间没有子shell产生
再改一下:(cat </dev/zero;随便跟一个命令)
这样cat进程前就多了一个子shell 为什么?
外部命令会fork出子shell 这个说法是不是不够准确
当一个外部命令在子shell中 并且独占这个子shell时 不会再fork了 而是直接exec调用这个外部命令替换它所在的子shell?

2.
执行外部命令时fork出的子shell 是不是就是bash?
我在终端里执行:bash
这个过程是怎样的?
按我的理解是 /bin/bash是一个外部命令 所以先fork出一个子shell 再exec调用bash代替了这个子shell
如果fork出的这个子shell也是bash 那这个过程就是用bash替换了bash?

3.
当前目录下随便建立一文件temp
执行while true;do cat temp;done
cat是外部命令 而查看进程发现这个命令没有产生子进程 这是为什么?

4.
管道和子shell
管道前后的命令是不是都会在子shell中运行? 还是只有管道后才在子shell中运行?
网上有很多文章说管道前后会并发两个子shell
我想不出合适的命令去验证 怎么写一个管道命令 管道前使用内建命令并使这个命令保持在进程中?

求教育.... :em06
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: 关于read命令的两个问题

#13

帖子 fnan » 2011-12-07 5:12

关于进程环境 我好像是明白了 不知道是不是这样理解:
执行外部命令时有个fork-exec的步骤 经过exec函数处理后 代替了fork出的子shell 所以进程环境还是之前父shell的
执行外部命令不需要子shell,外部命令本身就是子进程。
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: 关于read命令的两个问题

#14

帖子 fnan » 2011-12-07 5:28

关于执行bash和sh运行脚本后 $BASH_SUBSHELL值仍然为0 我是按以下来理解的 不知道对不对:
fork出来的子shell $BASH_SUBSHELL的值会+1
执行bash后和用sh运行脚本时 fork出了子shell 这个子shell里的$BASH_SUBSHELL也会+1 但是随后会触发exec exec调用了bash代替了这个子shell
这个bash是初始的 所以$BASH_SUBSHELL的值又回到了默认的0
应该没有触发exec,这时有两个进程环境,都是0,即是说互相独立的,就算确是父子进程关系:
kose1-2@kose1-2-desktop:~$ echo $$
3906
kose1-2@kose1-2-desktop:~$ bash <<'eof'
echo $$'的层次='$BASH_SUBSHELL
ps -ef|grep -E '\bbash\b'
eof
3936的层次=0
kose1-2 3906 3904 0 16:15 pts/0 00:00:00 bash
kose1-2 3936 3906 0 16:27 pts/0 00:00:00 bash
kose1-2@kose1-2-desktop:~$
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: 关于read命令的两个问题

#15

帖子 fnan » 2011-12-07 5:42

1.
前面您提到的例子:cat </dev/zero 创建了一个子进程 进程环境是父shell的
如果这样:(cat </dev/zero)呢?
我理解的是括号()fork了一个子shell 这个子shell中的cat是外部命令 所以应该再fork一个shell 称为孙shell吧 然后exec函数执行cat代替了这个孙shell
但是ps查看进程发现 cat这个进程的父shell还是最开始的运行(cat </dev/zero)的那个shell 它们之间没有子shell产生
再改一下:(cat </dev/zero;随便跟一个命令)
这样cat进程前就多了一个子shell 为什么?
外部命令会fork出子shell 这个说法是不是不够准确
当一个外部命令在子shell中 并且独占这个子shell时 不会再fork了 而是直接exec调用这个外部命令替换它所在的子shell?
#不一定产生子shell,(cat </dev/zero) 就不会,因为没有环境操作有关的东西,cat本身是子进程,(cat <<<$BASH_SUBSHELL) 就不一样了,两个命令以上就会有子shell,为了确保命令操作是子进程吧,比如可能是内建命令。
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
回复