书上学到的一条命令,将一个目录下的目录树,创建到另一个目录下,但有点不解。

sh/bash/dash/ksh/zsh等Shell脚本
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: 书上学到的一条命令,将一个目录下的目录树,创建到另一个目录下,但有点不解。

#16

帖子 fnan » 2012-03-28 20:48

cao627 写了:看过了

代码: 全选

find  ....  -exec mkdir ....{} \;
看来find命令的作者是考虑到并解决了空格文件名带来的麻烦的
#避开了shell的空格分割,用引号也有这效果。
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
头像
lilydjwg
论坛版主
帖子: 4258
注册时间: 2009-04-11 23:46
系统: Arch Linux
联系:

Re: 书上学到的一条命令,将一个目录下的目录树,创建到另一个目录下,但有点不解。

#17

帖子 lilydjwg » 2012-03-28 21:12

cao627 写了:

代码: 全选

mkdir -vp /home/someone/lt/Whitespace Matters
这条命令会这样执行:
在 /home/someone/lt/目录下创建Whitespace
在当前目录下创建Matters

如果{}只是简单把find找到的内容替换进来,那么我也会在执行find .... -exec mkdir ....{} \;后,在当前目录下生成类似Matters这种由于文件名空格产生的文件
但是没有,说明{}解决了这个问题,而{}是find的一部分,所以 说:“看来find命令的作者是考虑到并解决了空格文件名带来的麻烦的”
find 执行的是这样子的(源码未下载;以下是我的推测):
[c]
int i;
for(i = 0; strcmp(exec_cmd_args, ";") == 0; i++)
if(strcmp(exec_cmd_args, "{}") == 0)
exec_cmd_args = file_path;
exec_cmd_args = NULL;
execvp(exec_cmd_args[0], exec_cmd_args);
[/c]

所以 find 根本不用管文件名中的空格或者什么其它的东西。对于 C 字符串唯一特别的 NULL 字符不会出现在文件名中。

补充:你可以试试以下代码是否会出问题:
[c]
#include<unistd.h>

int main(int argc, char **argv){
execlp("mkdir", "mkdir", "-p", "some/dir contains whitespace", NULL);
return 0;
}
[/c]
cao627
帖子: 992
注册时间: 2007-12-05 10:57
系统: ubuntu14.04
来自: 金山

Re: 书上学到的一条命令,将一个目录下的目录树,创建到另一个目录下,但有点不解。

#18

帖子 cao627 » 2012-03-28 22:00

自由建客 写了:cao627, 你没理解那个道道
那个道道是是命令最后的\;吗?

\ 的作用是什么呢?

-exec command {} \; 是find命令的一部分吗? 即离开find命令 -exec command {} \;是否有意义?
aerofox
帖子: 1453
注册时间: 2008-05-24 8:30

Re: 书上学到的一条命令,将一个目录下的目录树,创建到另一个目录下,但有点不解。

#19

帖子 aerofox » 2012-03-29 13:11

cao627 写了:
自由建客 写了:cao627, 你没理解那个道道
那个道道是是命令最后的\;吗?

\ 的作用是什么呢?

-exec command {} \; 是find命令的一部分吗? 即离开find命令 -exec command {} \;是否有意义?
-exec command {} \; 是 find 命令的一部分。\ 的作用是防止 shell 对分号进行解释。

find 并没有刻意去处理文件名中的空格,相反,是 shell 刻意去处理空格,把空格当成参数之间的分隔符,所以才需要加引号。而 find 只是在 -exec 后面遇到 {} 时,把文件名原封不动的传给它调用的命令,而且 {} 对 shell 没有特殊含义,所以从不需要引号。

整个过程是,不管 {} 加不加引号,shell 都把不带引号的 {} 传给 find,然后 find 又把 {} 解释为文件名,换成文件名(不管里面有没有空格、方括号、问号等等对 shell 来说是特殊字符的东西)后,原样传给它启动的命令。
头像
自由建客
帖子: 13468
注册时间: 2008-07-30 23:21
系统: Debian stable AMD64

Re: 书上学到的一条命令,将一个目录下的目录树,创建到另一个目录下,但有点不解。

#20

帖子 自由建客 » 2012-03-29 20:57

那个道道是是命令最后的\;吗?

\ 的作用是什么呢?

-exec command {} \; 是find命令的一部分吗? 即离开find命令 -exec command {} \;是否有意义?
剥洋葱一样,只要你明白哪些会被 shell 处理,哪些会被应用程序处理。
末尾的 \; 会被 shell 处理,传给 find 的只有分号。find 就以分号做命令分隔符。
cao627
帖子: 992
注册时间: 2007-12-05 10:57
系统: ubuntu14.04
来自: 金山

Re: 书上学到的一条命令,将一个目录下的目录树,创建到另一个目录下,但有点不解。

#21

帖子 cao627 » 2012-03-30 12:13

然后 find 又把 {} 解释为文件名,换成文件名(不管里面有没有空格、方括号、问号等等对 shell 来说是特殊字符的东西)后,原样传给它启动的命令。
问题是:

比如

用find命令找到唯一的文件夹/somedir/Whitespace Matters

继续 -exec mkdir /somepath {} \;

然后/somedir/Whitespace Matters会替换掉{}对吗?

然后mkdir命令执行的是 makdir /somepath/somedir/Whitespace Matters对吗

makdir /somepath/somedir/Whitespace Matters 会被shell解析成:

mkdir /somepath/somedir/Whitespace 和 mkdir Matters
即当前目录下莫名其妙被创建个Matters目录

但实验结果是只在/somepath/somedir/下创建’Whitespace Matters‘

如果你用管道把find 的结果传给 mkdir
那么就会在执行这条管道命令的当前目录下创建Matters了

问题是 find ... -exec mkdir /somepath/ {} \; 中Whitespace Matters问题是怎么被解决的?

13楼
find 并不会调用 shell,而是直接 execv,所以毫无问题
应该是在解释这个问题
似乎这样理解:
find查找到的内容使用-exec后并不是调用shell 把“表达”打印到屏幕上{}的位置
是经过execv直接把“观念”传给{}的
find 并没有刻意去处理文件名中的空格,相反,是 shell 刻意去处理空格,把空格当成参数之间的分隔符,所以才需要加引号。
看来aerofox 也在试图向我说明这点
但没有类比的描述,这个问题对于普通用户确实有点难说清的
谢谢
上次由 cao627 在 2012-03-30 14:54,总共编辑 1 次。
头像
lilydjwg
论坛版主
帖子: 4258
注册时间: 2009-04-11 23:46
系统: Arch Linux
联系:

Re: 书上学到的一条命令,将一个目录下的目录树,创建到另一个目录下,但有点不解。

#22

帖子 lilydjwg » 2012-03-30 14:48

cao627 写了:
问题是:

比如

用find命令找到唯一的文件夹/somedir/Whitespace Matters

继续 -exec mkdir /somepath {} \;

然后/somedir/Whitespace Matters会替换掉{}对吗?

然后mkdir命令执行的是 makdir /somepath/somedir/Whitespace Matters对吗

makdir /somepath/somedir/Whitespace Matters 会被shell解析成:

mkdir /somepath/somedir/Whitespace 和 mkdir Matters
即当前目录下莫名其妙被创建个Matters目录

但实验结果是只在/somepath/somedir/下创建’Whitespace Matters‘

如果你用管道把find 的结果传给 mkdir
那么就会在执行这条管道命令的当前目录下创建Matters了

问题是 find ... -exec mkdir /somepath/ {} \; 中Whitespace Matters问题是怎么被解决的?

13楼
find 并不会调用 shell,而是直接 execv,所以毫无问题
应该是在解释这个问题
似乎这样理解:
find查找到的内容使用-exec后并不是调用shell 把“表达”打印到屏幕上{}的位置
是经过execv直接把“观念”传给{}的
你看了我在 17 楼贴的第二段代码没?
cao627
帖子: 992
注册时间: 2007-12-05 10:57
系统: ubuntu14.04
来自: 金山

Re: 书上学到的一条命令,将一个目录下的目录树,创建到另一个目录下,但有点不解。

#23

帖子 cao627 » 2012-03-30 15:07

你看了我在 17 楼贴的第二段代码没?
恩懂了
mkdir 并没有刻意去处理文件名中的空格,相反,是 shell 刻意去处理空格,把空格当成参数之间的分隔符,
mkdir /Whitespace Matters
是shell解释这条命令将Whitespace Matters中的空格做分割符了
而在find ... -exec mkdir {} \; (如果find ... 查找的结果是/Whitespace Matters)
执行mkdir时 shell已经不再介入,去误导mkdir “你先去/下创建Whitespace 然后再在当前目录创建Matters”
mkdir只是安安静静在执行它的本质 execlp("mkdir", "mkdir", "-p", "findout", NULL);
回复