LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2271|回复: 11

ls ,这个最简单的命令到底输出什么?高手能否指点迷津?

[复制链接]
发表于 2007-5-2 23:15:06 | 显示全部楼层 |阅读模式
请输入以下命令:
[jqq@localhost ~]$ ls
demo  Desktop  dic.txt  hte  qt  soc   //看清了,每项之间是空格
[jqq@localhost ~]$ ls | more
demo
Desktop
dic.txt
hte
qt
soc                                //怎么用管道重定向到more后变成回车了?
[jqq@localhost ~]$ ls > ls_tmp      //重定向到文件看看
[jqq@localhost ~]$ cat ls_tmp
demo
Desktop
dic.txt
hte
ls_tmp
qt
soc                            //用cat看也是回车,是不是cat错了,再用gedit看看
[jqq@localhost ~]$ gedit ls_tmp
//用gedit看也是回车,看来确实是回车了.可是直接ls却是空格.是否是terminal的问题,还是重定向时是回车,不重定向是空格?

能否指点一下,小弟不胜感激!
发表于 2007-5-3 00:06:41 | 显示全部楼层
you can man ls and see the reason. I believe ls is doing column list to tty but not to redirect. ls -1 shows one per line.
回复 支持 反对

使用道具 举报

发表于 2007-5-3 00:18:49 | 显示全部楼层
我的理解。
ls输出是回车没错,但是shell里使用的回显程序是echo,echo会把没有加引号的换行删去。

你可以试试
a=$(ls)
echo $a

echo "$a"
的区别。

这好像在Advanced Bash 里有
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-5-3 02:11:13 | 显示全部楼层
楼上说得非常有道理.原来shell是用echo命令回显啊,我还以为这是shell自身具备的功能呢.

但是我还是有1点不明白:
"echo会把没有加引号的换行删去"

当我们l输入$echo string...后,再打enter键,echo命令执行.打enter键相当于输入一个换行吧,echo(也许是shell本身)遇到换行就结束了,但echo `ls`却输出了换行,并没有结束.`ls`中的换行与我们直接打入的换行有什么区别?为什么前者结束了而后者没有?不懂.莫非 ls 输出的换行与我们击 enter  键打入的不同.回车是回到行首,换行是垂直进入下一行.回车,回车,到底输入的是回车还是换行,抑或回车换行,好乱.

$ls >ls_tmp
$cat >cat_tmp<<eof
>a
>b
>c
>eof
$gedit gedit_tmp  //同样输入a,b,c,每行一个

$xxd ls_tmp
0000000: 6465 6d6f 0a44 6573 6b74 6f70 0a64 6963  demo.Desktop.dic
0000010: 2e74 7874 0a68 7465 0a6c 735f 746d 700a  .txt.hte.ls_tmp.
0000020: 7174 0a73 6f63 0a74 6d70 0a              qt.soc.tmp.
$xxd cat_tmp
0000000: 610a 620a 630a                           a.b.c.
$xxd gedit_tmp
0000000: 610a 620a 630a                           a.b.c.

从16进制看,都是0a--LF换行,而没有0d--CR换行.也就是说我们打enter键输入的只有换行,没有回车.搞不懂啊,只有换行为什么新的一行从行首开始?以前在win下编程就遇到过这种情况:有的程序用回车,有的用换行,有的用回车换行,根本不知道到底该怎么用.啊,在lin下也被搞乱了.有哪位能深析一下啊?
回复 支持 反对

使用道具 举报

发表于 2007-5-3 04:20:30 | 显示全部楼层
linefeed '\n' is not the same as '\r' return. when you type cmds, it return \r which will send the string to the shell interpreter but if you are in readline mode or editing mode, enter does not do \r but \n which will send a linefeed.
回复 支持 反对

使用道具 举报

发表于 2007-5-3 04:22:38 | 显示全部楼层
Post by iveney
我的理解。
ls输出是回车没错,但是shell里使用的回显程序是echo,echo会把没有加引号的换行删去。

你可以试试
a=$(ls)
echo $a

echo "$a"
的区别。

这好像在Advanced Bash 里有


Its actually controlled through IFS. the internal field separator. try this:
IFS=""; echo $(ls); echo "$(ls)". They become the same. stuff in "" will take literally but if there is no "", then shell takes the default separater which is set in IFS.
回复 支持 反对

使用道具 举报

发表于 2007-5-3 04:24:00 | 显示全部楼层
but still, even if you reset IFS, a plain ls will still just output column list, this is probably hard coded...
回复 支持 反对

使用道具 举报

发表于 2007-5-3 13:10:02 | 显示全部楼层
Post by jqq850226
楼上说得非常有道理.原来shell是用echo命令回显啊,我还以为这是shell自身具备的功能呢.

但是我还是有1点不明白:
"echo会把没有加引号的换行删去"

当我们l输入$echo string...后,再打enter键,echo命令执行.打enter键相当于输入一个换行吧,echo(也许是shell本身)遇到换行就结束了,但echo `ls`却输出了换行,并没有结束.`ls`中的换行与我们直接打入的换行有什么区别?为什么前者结束了而后者没有?不懂.莫非 ls 输出的换行与我们击 enter  键打入的不同.回车是回到行首,换行是垂直进入下一行.回车,回车,到底输入的是回车还是换行,抑或回车换行,好乱.

$ls >ls_tmp
$cat >cat_tmp<<eof
>a
>b
>c
>eof
$gedit gedit_tmp  //同样输入a,b,c,每行一个

$xxd ls_tmp
0000000: 6465 6d6f 0a44 6573 6b74 6f70 0a64 6963  demo.Desktop.dic
0000010: 2e74 7874 0a68 7465 0a6c 735f 746d 700a  .txt.hte.ls_tmp.
0000020: 7174 0a73 6f63 0a74 6d70 0a              qt.soc.tmp.
$xxd cat_tmp
0000000: 610a 620a 630a                           a.b.c.
$xxd gedit_tmp
0000000: 610a 620a 630a                           a.b.c.

从16进制看,都是0a--LF换行,而没有0d--CR换行.也就是说我们打enter键输入的只有换行,没有回车.搞不懂啊,只有换行为什么新的一行从行首开始?以前在win下编程就遇到过这种情况:有的程序用回车,有的用换行,有的用回车换行,根本不知道到底该怎么用.啊,在lin下也被搞乱了.有哪位能深析一下啊?


你输入一个命令后按的回车,发生的具体动作是,shell检测到输入了一个回车,代表一个命令的结束,然后进行命令解释执行。

UNIX style的换行跟windows不同。win是crlf,Unix是cr
回复 支持 反对

使用道具 举报

发表于 2007-5-3 13:11:20 | 显示全部楼层
Post by yongjian
Its actually controlled through IFS. the internal field separator. try this:
IFS=""; echo $(ls); echo "$(ls)". They become the same. stuff in "" will take literally but if there is no "", then shell takes the default separater which is set in IFS.


GOoooOd!!! Thanks for your supplement!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-5-3 17:49:16 | 显示全部楼层
Post by yongjian
Its actually controlled through IFS. the internal field separator. try this:
IFS=""; echo $(ls); echo "$(ls)". They become the same. stuff in "" will take literally but if there is no "", then shell takes the default separater which is set in IFS.


但是你这句话并没有解释为什么没有改IFS时有与没有引号("")结果会不同啊.
以我的理解,shell本身不会用IFS去分割引号里的内容.还有如果用IFS=""把IFS设为空,shell是根本不去分割,而不是逐字地(literally)分割,所以有没有引号("")结果会一样.看以下命令:
$t="a b c"
$for i in $t ; do echo "["$i"]" ; done
[a]

[c]
$for i in "$t" ; do echo "["$i"]";done
[a b c]
$IFS=""; for i in $t ; do echo "["$i"]" ;done
[a b c]

另外,在debian手册中给了一个例子:
...........
shell 也使用 IFS 来分开参数扩展、命令替换和算术扩展的结果集。但在被单引号或双引号引用的单词内,不会发生这种情况。 默认的 IFS 值是: <space>、 <tab> 和 <newline> 。
请小心使用这个 shell IFS 技巧。 当 shell 解释部分脚本作为它的输入时(此句不懂),奇怪的事情将会发生。

$ IFS=":,"                        # 使用 ":" 和 "," 作为 IFS
$ echo IFS=$IFS,   IFS="$IFS"     # echo 是 Bash 内建的
IFS=  , IFS=:,                   #,前有2个空格

中间那个","是怎么回事? 再看下面4个命令:

$echo IFS=$IFS: , IFS="$IFS"   
IFS=    , IFS=:,               #,前有3个空格
$echo IFS=$IFS : , IFS="$IFS"  #中间的":,"与前面的$IFS有空格
IFS=   : , IFS=:,     #:前有2个空格

$echo IFS=$IFS, : IFS="$IFS"
IFS=  , : IFS=:,     #,前有2空格
$echo IFS=$IFS , : IFS="$IFS"
IFS=  , : IFS=:,     #,前有2空格,跟上面一样

从这4个命令可以看出,中间的","无论是否与前面的IFS=$IFS相邻都没当作splitter,而":"则不同,与IFS=$IFS相邻时被解释成splitter,而不相邻时则没有.是否IFS=":,"这句有先后顺序?改为IFS=",:"再运行同样命令结果还是一样,真让人摸不着规律.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表