文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>关于IFS的疑问

关于IFS的疑问

时间:2007-10-18  来源:brain2007

[精彩] 关于IFS的疑问

http://www.chinaunix.net 作者:li2002  发表于:2007-09-19 10:55:39
【发表评论】 【查看原文】 【Shell讨论区】【关闭】

正在看网中人的13问,看到IFS有一些疑问,请教大家:

1、如果我没保存原IFS,怎么用语句直接设置IFS
IFS="  \n\t"
这样设对吗,是恢复默认的吗??

2、我看说明中有:
IFS=
IFS=;
是一样的意思,我不明白既然一样为什么要用第二种形式呢??有什么特殊意义吗??还是仅用来区别与IFS=";"的不同。
第二种形式中的分号怎么解释??

3、默认IFS时如果
A="   aaa"
echo $A
结果当然是
aaa
前面没有空格
但是
A=";;;;aaa"
IFS=";"
echo $A 时
结果却是
    aaa
前面有四个空格,按道理不是应该没有空格吗?这是怎么回事呢??

4、文件b的内容是
echo $*
echo $1

#IFS=";"
#./b  111    22222

结果和不设IFS是一样的,都是
111 2222    (--中间一个空格)
111
为什么在执行命令时IFS不起作用呢??
我想的是如果起了作用,shell不就把整行看做无参数的命令了吗,shell就应该说找不到该命令了,呵呵,当然不想这样,我只是试验一下,这里为什么就不起作用了呢???

 :em14:

 網中人 回复于:2005-03-15 22:53:25

1) 你可先將 IFS 存起來: old_IFS="$IFS"
要取回時再設 IFS="$old_IFS"
(記的雙引號一定要設哦)

2) 若有兩個 command 打在同一行就用到.

3) 這要扯到 command 與 shell 在 IFS 的認定及處理的差異了. 
嗯, 我也講不出個所以然... sorry.
我認為 echo 是在 subshell 裡執行的, 而 subshell 在 initial 時會採用原有 IFS . 
不過, 我不確定啦.
你可比較如下兩行:
IFS=";"; echo $A
IFS=";" echo $A
差別在於少了一個 ;  , 也就是第二行改變了 subshell 的 IFS 而第一行則沒有. 

4) 你用 "$*" 才能發現有何不同, 且將 IFS 設在 b 裡面, 再比較如下:
./b 111 & & 222
./b "111 & & 222"

在 man bash 裡, 關於 $* 的說法如下:
        *      Expands to the positional parameters, starting from

one. When the expansion occurs within double

quotes, it expands to a single word with the value

of each parameter separated by the first character

of the IFS special variable. That is, "$*" is

equivalent to "$1c$2c...", where c is the first

character of the value of the IFS variable. If IFS

is unset, the parameters are separated by spaces.

If IFS is null, the parameters are joined without

intervening separators.



 lightspeed 回复于:2005-03-16 03:31:53

IFS 的确叫人误解, 问题也不少.  最好是不要改.

引用:原帖由 "li2002" 发表:
3、默认IFS时如果
A="   aaa"
echo $A
结果当然是
aaa
前面没有空格
但是
A=";;;;aaa"
IFS=";"
echo $A 时
结果却是
   aaa
前面有四个空格,按道理不是应该没有空格吗?这是怎么回事呢??
 

这是由于作为 IFS 的空白字符 ( blank, tab, newline) 与其他 IFS 字符行为不同:

1.  IFS 空白在输入的开始和结束处忽略。
2.  输入中每个非 IFS 空白的 IFS 字符,以及任何相邻的 IFS 空白,定界一个字段。
3. 非零长度 IFS 空格对字段进行定界。

更多例子,参考 Advanced Bash-Scripting Guide

http://www.tldp.org/LDP/abs/html/internalvariables.html#IFSH
http://www.tldp.org/LDP/abs/html/internalvariables.html#IFSEMPTY

引用:原帖由 "li2002" 发表:

我想的是如果起了作用,shell不就把整行看做无参数的命令了吗,shell就应该说找不到该命令了,呵呵,当然不想这样,我只是试验一下,这里为什么就不起作用了呢??? 

1. IFS 只对参数扩展有作用, $* 是 $1 - $n, 不包括 $0

2. IFS 对参数位置无作用. 参数位置由空白字符及有无" " 决定

所以不可能出现你想象的情况. 

引用:原帖由 "li2002" 发表:

4、文件b的内容是
echo $*
echo $1

#IFS=";"
#./b  111    22222

结果和不设IFS是一样的,都是
111 2222    (--中间一个空格)
111
为什么在执行命令时IFS不起作用呢??
 

如 netman 所言,IFS 语句应加在程序中.

在 "$*" 扩展时行为不同 (如较新版本的 bash, ksh). 这是 POSIX 标准.

但由于历史原因, 有些版本的 shell  并不按 man page 中所声明的那样扩展,
而是只用空格,  这样有无 IFS 对 "$*" 无影响.

refer to: POSIX white paper 
<<Shell Command Language: Migrating from the System V Shell to the POSIX Shell>>

 網中人 回复于:2005-03-16 10:37:23

呵... 受教受益!

感謝 lightspeed 兄的說明及相關資訊!  ^_^

 waker 回复于:2005-03-16 10:42:00

行家伸伸手,便知有没有,学到了:D

 li2002 回复于:2005-03-16 14:05:52

FT!写了一大段话因为session超时没有了,5555~~~~
这是第二次写:
谢谢网中人和版主的回答,真是热心人啊!!
不过还有些问题不明白:
网中人回答我第三问
A=";;;;aaa" 
IFS=";" 
echo $A 时 
结果却是 
   aaa 


你可比較如下兩行:

IFS=";"; echo $A

IFS=";" echo $A

差別在於少了一個 ; , 也就是第二行改變了 subshell 的 IFS 而第一行則沒有

.


我的结果是
$A=";;;;aaa"
$ IFS=""
$ IFS=";" echo $A
;;;;aaa

$ IFS=""
$ IFS=";";echo $A
aaa

结果好像和netman说的意思相反呢,
我想问一下,这两种情况有何不同??无分号分隔是一个子进程里执行,有分号的在两个子进程里执行??
netman的意思是一个进程的IFS变量由其父进程决定,而不是由本进程中设置的IFS决定??

还有第四问中回答说将IFS设置放在b中,这与写在命令行中有何区别?这还应该涉及到子进程的问题吧。如果b中有两行命令,在执行./b后,系统 会产生一个子进程(父进程等待),是在这一个子进程中依次执行b中的命令行,还是在执行每行时都再产生各自的子进程执行命令呢??这与在命令行中一个一个 命令输入执行又有什么区别??

netman说的subshell与我说的子进程是一个意思吧??

再帮我分析一下两个语句间是空格、分号、&&、||的进程执行情况吧。

 li2002 回复于:2005-03-16 14:15:04

lightspeed 说的IFS的whitespace和用其他字符做IFS处理是不一样的,看了链接我明白了,是不能用whitespace类推,但我觉得还是不能很好的解答为什么要出现4个空格的问题。
是不是其他字符做IFS时,在字符串中与IFS相同的字符显示时都由空格替代??这是一条规则??

老大说的这一句:
     

2. IFS 对参数位置无作用. 参数位置由空白字符及有无" " 决定



是什么意思啊??跟在命令后的不都是参数吗?是指对$*,$1....$n不起作用是吗??对$*来说,分隔符是不能指定的是吗??

 li2002 回复于:2005-03-17 14:10:17

up一下

 網中人 回复于:2005-03-17 21:03:36

呵, 太深了... 
我也答不上來~~~  ^_^

 aerofox 回复于:2005-03-17 21:48:45

的确,lightspeed讲得很明白了。
引用:原帖由 "li2002"]但我觉得还是不能很好的解答为什么要出现4个空格的问题。
 发表:

关于这一点,可以这么理解:
A=";;;;aaa" 

IFS=";"

echo $A

在最后一条命令中,传给echo的命令行参数为$1="";$2="";$3="";$4="";$5="aaa"。
执行过程等效于
printf "%s" "$1"

for arg in "$2" "$3" "$4" "$5"; do

printf " %s" "$arg"

done

printf "\n"

也就是说,在除第一个参数外的每个参数前,echo自动加一个空格与前一参数分隔。这样就产生了四个前导空格。

 li2002 回复于:2005-03-17 22:41:36

看了aerofox说明觉得有些道理,感谢!!
不过我把这个拿到sco unix(/bin/sh)下做试验,发现前面没有空格,看来这个在不同的系统下不同。
那位能分析一下
  A=";;;;aaa"
  IFS=;
  IFS=";"; echo $A  <---------
  IFS=; 
  IFS=";" echo $A    <--------- 少一个分号
两者的结果为什么不同,第一个是
    aaa  (前面4个空格)
第二个是
;;;;aaa

这两句从进程的角度在执行时有什么不同??我不知道。

 lightspeed 回复于:2005-03-18 02:35:18

引用:原帖由 "li2002" 发表:
看了aerofox说明觉得有些道理,感谢!!


aerofox 说对了。

引用:原帖由 "li2002" 发表:

不过我把这个拿到sco unix(/bin/sh)下做试验,发现前面没有空格,看来这个在不同的系统下不同。


这是纯 sh (不是 bash, ksh 的 sh 兼容模式)  与 bash/ksh/zsh 的不同引起的。  请看 BASH FAQ 中的一段:

Implementation differences:

bash splits only the results of expansions on IFS, using 
        POSIX.2 field splitting rules; sh splits all words on IFS

例如: sh 下

A=";;;;aaaa"

echo $A

分解为 

echo ""  ""  ""  ""  aaaa  (其中 ""  为空字符, 并不作为参数)

相当于 

echo                  aaaa

相当于

echo aaaa

因此结果就是前面没有空格的 aaaa 了.

同理, 如果

# a=";;;;;;a;;;;;;;;;b;;;;;;;;;;;;;;;;;;;;;c;;;;;;;;;;;;;;;;;;"
# echo $a
a b c

引用:原帖由 "li2002" 发表:

那位能分析一下
 A=";;;;aaa"
 IFS=;
 IFS=";"; echo $A  <---------
 IFS=;
 IFS=";" echo $A    <--------- 少一个分号
两者的结果为什么不同,第一个是
   aaa  (前面4个空格)
第二个是
;;;;aaa

这两句从进程的角度在执行时有什么不同??我不知道。


  aaa  (前面4个空格)  -- 这个结果 aerofox  已说明了.

按说  IFS=";" echo $A  也应得到上面的结果. 
如果在 N 年前,  二者的确是相同的. 

但由于 IFS 经常 被 hecker 用 形如  IFS=/; export IFS
的语句在 heck program 中,   对系统的安全是个隐患. 因此现在版本的 ksh, bash  都不允许 export  IFS.  (很容易验证). 
IFS=";" echo $A  中的 IFS=";" 实际也是不起作用的.

因此 IFS=";" echo $A  就是和  echo $A  一样的效果.

 li2002 回复于:2005-03-18 09:25:57

lightspeed真是高手,解释得非常清楚,把我得疑问解除了,感谢!

我还有一个由上面引出来得问题想请教版主,不要嫌我烦啊。

一个shell文件1.sh,内容是
echo $A

在命令中执行(bash)
测试1:
$ A="aaa"
$ A="bbb"  ./1.sh
$ echo $A
显示:
bbb
aaa

在A="bbb"  ./1.sh中定义的A相当与在fork子进程中定义的局部变量,等同与把A="bbb" 写入1.sh的第一行中。

测试2:
$ A="aaa"
$ A="bbb"  . ./1.sh
$ echo $A
显示:
bbb
aaa

按我的想法,1.sh执行在本进程中执行,其中的A在被改变后就一直有效,所有在第二行就应该显示"bbb"了。但结果仍显示原来的值,这应该是bash从安全性上的考虑吗??说明1.sh在执行时并没有覆盖原来的A,而是用了另外的内存空间。
把此例拿到sco unix(sh)下执行时第二行的显示就是bbb,覆盖了原来的A,这好像证明了版主的意见:bash安全性提高了。

这其实还不是我原来想要问的。再看测试3
$ A="aaa"
$ A="bbb"  echo $A
$ echo $A
显示:
aaa
aaa
就是我把1.sh的内容执行放在命令行上。结果显示的却是原来的值"aaa",我想不通了,在执行此句时不应该也执行1.sh一样吗,我想问执行这一句不也是先fork再执行的吗?看意思它好像是:
1)先定义局部变量A(值是bbb)
2)fork进程,由于原环境中有A变量,所有就覆盖了定义第一步定义的局部变量A  《----但我原来的A并没有export,为什么要理它呢??
3)显示结果aaa

我想问的重点是:
A="bbb" echo $A
执行时是先赋值A,再fork进程,还是先fork进程,再定义A??
把echo $A直接写在命令行上与写在脚本中再执行脚本有什么不同???

 lightspeed 回复于:2005-03-18 11:00:40

引用:原帖由 "li2002" 发表:

这其实还不是我原来想要问的。再看测试3
$ A="aaa"
$ A="bbb"  echo $A
$ echo $A
显示:
aaa
aaa
就是我把1.sh的内容执行放在命令行上。结果显示的却是原来的值"aaa",我想不通了,在执行此句时不应该也执行1.sh一样吗,我想问执行这一句不也是先fork再执行的吗?看意思它好像是:
1)先定义局部变量A(值是bbb)
2)fork进程,由于原环境中有A变量,所有就覆盖了定义第一步定义的局部变量A  《----但我原来的A并没有export,为什么要理它呢??
3)显示结果aaa

我想问的重点是:
A="bbb" echo $A
执行时是先赋值A,再fork进程,还是先fork进程,再定义A??
把echo $A直接写在命令行上与写在脚本中再执行脚本有什么不同???

解释的不对。

A="bbb" echo $A

$A 是在本 shell 中扩展的。  这句等同于

A="bbb" echo aaa

A="bbb"  是将 echo 命令所处环境变量 A 设为 bbb,  
但 echo 并不用此变量,  而是用 $1 就是 aaa.

 網中人 回复于:2005-03-18 12:51:55

對, 別忘了"替換 & 重組"這個特性.
在 CR 之前, command line 已被重組為:
A="bbb" echo aaa

不妨來比較一下:
[netman@www tmp]$ A=aaa

[netman@www tmp]$ A="bbb" echo $A

aaa

[netman@www tmp]$ A=aaa

[netman@www tmp]$ A="bbb"; echo $A

bbb

[netman@www tmp]$ A=aaa

[netman@www tmp]$ A="bbb" eval echo \$A

bbb


p.s. 感謝 lightspeed & aerofox 兄的解說! 受益非淺!  ^_^

 li2002 回复于:2005-03-18 14:35:49

知道了,我把最基本的原则忘了,汗啊。。。。。

 ericshei 回复于:2005-08-10 17:07:31

name=value command 其name=value只有command會參考(而且只這次會參考).

所以下面的例子才會如此:
$ A="aaa"
$ A="bbb"  . ./1.sh
$ echo $A
显示:
bbb
aaa 

而$ A="bbb"  ./1.sh應該也是一樣的情形,只是差在有沒有sub shell中執行而己.

初到貴寶地,請多指教!  f^^

 heijude 回复于:2005-08-10 19:41:18

WA,一群牛人!!学习~~~~~~~~~~~~~~~~

 ericshei 回复于:2005-08-10 20:48:48

引用:原帖由 "lightspeed" 发表:

1.  IFS 空白在输入的开始和结束处忽略。
2.  输入中每个非 IFS 空白的 IFS 字符,以及任何相邻的 IFS 空白,定界一个字段。
3. 非零长度 IFS 空格对字段进行定界。


引用:原帖由 "lightspeed" 发表:

1. IFS 只对参数扩展有作用, $* 是 $1 - $n, 不包括 $0

2. IFS 对参数位置无作用. 参数位置由空白字符及有无" " 决定

所以不可能出现你想象的情况. 


不好意思,lightspeed兄,是否能再將上述的二段內容再做解釋,在下實在很想了解其中的義意.

另外bash在解析shell prompt與<CR>字符之間的內容時,是不是不參考IFS變量?但若其中有做變量替換時則會?因為在下的測試結果如下:

$ IFS=I

$ cdI/etc

-bash: cdI/etc: No such file or directory

I仍然不是IFS所以不能區分出command name(cd)及argument(/etc)

$ IFS=i

$ var="one tw three four five six seven"

$ for n in $var eight nine;do echo \["$n"\];done

[one tw three four f]

[ve s]

[x seven]

[eight]

[nine]

該例在做$var變量替換時,參考了IFS變量,以i區分出[one tw three four f]、[ve s]及[x seven]三個位置參數,但eight及nine仍不為所動.

說不定我若參透上面那二段話的意思,答案就出來了!  f^^

 ericshei 回复于:2005-08-12 17:17:18

自問自答!我想我都清楚了!

shell由stdin收進來的command line做解析,拆成字段.這一步是由一組固定的中介字符來區隔出不同的字段(其中包含white space).

接著進行後續的處理,其中包含了變數替換這一步,在這時會參考IFS變數來區分出其它的字段.

一切的解答都在O'Reilly bash 第七章呀!

 xy-coordinate 回复于:2005-10-15 11:00:06

O'Reilly bash 谁有中文版吗?

 styr 回复于:2005-10-15 13:53:57

真的是不好掌握,尤其是平台不同甚至版本不同,可能都稍有差异...
先了解一下基本的就行了,高深的一般用的少,实在不行就想别的办法先凑和一下吧

 pqxpqx 回复于:2006-12-11 11:58:45

各位的用心良苦,是我等今后成长的动力。

 shk2016 回复于:2007-09-19 10:55:39

学习ing


原文链接:http://bbs.chinaunix.net/viewthread.php?tid=512925
转载请注明作者名及原文出处
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载