2011-04-07 137 views
2

我在文件夹中有一堆文件,在子文件夹中,我试图做一些简单的快速复制/粘贴一段时间。命令行查找,sed,exec

内容是(太长,粘贴到这里):http://pastebin.com/4aZCPbwT

我试过下面的命令:

列出所有文件及其目录

find . -name '[!.]*'

替换所有实例“命名空间”与“测试:

find . -name '[!.]*' -print0 | sed 's/Namespace/Test/gI' | xargs -i -0 echo '{}'

我需要做的是:

替换如上所述的折叠名称,并将文件夹(包括文件)复制到其他位置。创建文件夹,如果它们不存在(他们很可能不会) - 但是,有一些我不需要,如./app,因为此文件夹存在。我可以使用-wholename'./app'。

当它们被复制时,我需要替换每个文件中的一些文本,与上面相同(命名空间与测试 - 也出现在文件中并保存它们当然)。

像这样的事情我会想象:

-print -exec sed -i 's/Namespace/Test/gI' {} \;

难道这三件事在一个班轮做什么?替换文件中的文本(命名空间< => Test),使用cp -p(不想写入文件夹)复制包括其目录的文件,但用上面的命名空间重命名每个目录/文件(命名空间< => Test)。

非常感谢:-)

+0

为什么浪费时间拿出一个衬垫......我只想写有'for'循环,甚至更好'python'脚本一个简单的bash脚本。这可以在'python'交互式shell中很好地完成。 – pajton 2011-04-07 21:47:21

+0

好吧,好点。只是似乎只是复制/粘贴东西到我的终端会更容易:-)。我的Bash技能并不强,所以我可能无法写出完整的脚本。我只能做小随机命令。 – Michael 2011-04-07 21:49:32

+0

你发布的命令表明你有一些技巧:) – pajton 2011-04-07 21:51:03

回答

1

除了描述如何下面艰苦冗长,这种方法也可能在于,它包括内置调试是唯一的。除了编译和保存到变量之外,它基本上不会执行任何它认为应该执行的命令,以执行所请求的工作。

它也明确地尽可能避免循环。除了sed递归搜索模式的多个匹配,据我所知没有其他递归。

最后,这完全是null分隔 - 它不会在除null以外的任何文件中的任何字符上脱机。我认为你不应该那样。

顺便说一句,这是真的很快。看:

% _mvnfind() { mv -n "${1}" "${2}" && cd "${2}" 
> read -r SED <<SED 
> :;s|${3}\(.*/[^/]*${5}\)|${4}\1|;t;:;s|\(${5}.*\)${3}|\1${4}|;t;s|^[0-9]*\(.*\)${5}|\1|p 
> SED 
> find . -name "*${3}*" -printf "%d\tmv %P ${5} %P\000" | 
> sort -zg | sed -nz ${SED} | read -r ${6} 
> echo <<EOF 
> Prepared commands saved in variable: ${6} 
> To view do: printf ${6} | tr "\000" "\n" 
> To run do: sh <<EORUN 
> $(printf ${6} | tr "\000" "\n") 
> EORUN 
> EOF 
> } 
% rm -rf "${UNNECESSARY:=/any/dirs/you/dont/want/moved}" 
% time (_mvnfind ${SRC=./test_tree} ${TGT=./mv_tree} \ 
> ${OLD=google} ${NEW=replacement_word} ${sed_sep=SsEeDd} \ 
> ${sh_io:=sh_io} ; printf %b\\000 "${sh_io}" | tr "\000" "\n" \ 
> | wc - ; echo ${sh_io} | tr "\000" "\n" | tail -n 2) 

    <actual process time used:> 
    0.06s user 0.03s system 106% cpu 0.090 total 

    <output from wc:> 

    Lines Words Bytes 
    115  362 20691 - 

    <output from tail:> 

    mv .config/replacement_word-chrome-beta/Default/.../googlestars \ 
    .config/replacement_word-chrome-beta/Default/.../replacement_wordstars   

注:以上function可能会要求GNU版本的sedfind妥善处理find printfsed -z -e:;recursive regex test;t电话。如果这些功能不适用于您,则可能会通过一些小的调整来重复功能。

这应该做你想做的所有事情,从头到尾用很少的大惊小怪。我做了forksed,但我也在练习一些sed递归分支技术,所以这就是我来到这里的原因。这有点像在理发店打折理发,我想。这里的工作流程:

  • rm -rf ${UNNECESSARY}
    • 我故意留出可能删除或销毁任何类型的数据的功能调用。你提到./app可能是不需要的。事先删除它或将它移动到其他地方,或者,您也可以通过编程以find的程序构建\(-path PATTERN -exec rm -rf \{\} \)例程,但这是您的全部。
  • _mvnfind "${@}"
    • 声明它的参数,并呼吁工人功能。 ${sh_io}尤其重要,因为它可以节省函数的返回。 ${sed_sep}紧随其后;这是一个任意字符串,用于在函数中引用sed的递归。如果${sed_sep}被设置为可能在您的任何路径或文件名中执行的值,那么请不要这么做。
  • mv -n $1 $2
    • 整个树从开始移动。这将节省很多头痛;相信我。您想要做的其他事情 - 重命名 - 只是文件系统元数据的问题。例如,如果你是从一个驱动器移动到另一个驱动器,或者跨越任何类型的文件系统边界,那么最好使用一个命令立即执行。这也更安全。请注意为mv设置的-noclobber选项;如书面所示,此功能不会将${SRC_DIR}放在${TGT_DIR}已存在的地方。
  • read -R SED <<HEREDOC
    • 我所在这里所有的命令sed的年代,以节省逃避麻烦并把它读成一个变量来养活下面的sed。下面的解释。
  • find . -name ${OLD} -printf
    • 我们开始find过程。通过find,我们只搜索任何需要重命名的内容,因为我们已经使用函数的第一个命令完成了所有的地方到位mv操作。例如,我们不是采取任何与find直接行动,如exec调用,而是用-printf动态构建命令行。
  • %dir-depth :tab: 'mv '%path-to-${SRC}' '${sed_sep}'%path-again :null delimiter:'
    • find后其定位直接建立我们所需要的文件,并打印出()我们需要处理您的重命名命令。添加到每行开头的%dir-depth将有助于确保我们不试图用尚未重命名的父对象重命名树中的文件或目录。 find使用各种优化技术来遍历文件系统树,但它不会以确保操作顺序返回我们需要的数据。这就是为什么我们未来...
  • sort -general-numerical -zero-delimited
    • 我们所有排序基于%directory-depthfind的输出,从而在最近的关系,$路径{} SRC首先工作。这避免了将文件放入不存在的位置的可能错误,并且最小化了递归循环的需要。 (事实上,你可能会捉襟见肘找到所有循环)
  • sed -ex :rcrs;srch|(save${sep}*til)${OLD}|\saved${SUBSTNEW}|;til ${OLD=0}
    • 我觉得这是整个脚本的唯一循环,它只遍历第二%Path为每个字符串打印,以防它包含多个可能需要替换的$ {OLD}值。我想象的所有其他解决方案都涉及第二个sed进程,虽然短暂的循环可能并不理想,但肯定会影响产卵和分叉整个进程。
    • 所以基本上sed在这里所做的就是搜索$ {sed_sep},然后,已经发现了它,保存它和所有字符遇到,直到找到$ {OLD},它然后用$ {NEW}取代。然后它返回$ {sed_sep}并再次查找$ {OLD},以防字符串中出现多次。如果未找到,则将修改后的字符串打印到stdout(然后再次捕获),并结束循环。
    • 这避免了必须解析整个字符串,并确保mv命令串,这需要包括$上半年{OLD}当然也包括它,并且所述第二半被改变多次是必须擦除mv的目标路径中的$ {OLD}名称。
  • sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
    • 两个-exec通话发生在这里没有第二个fork。在第一,正如我们所看到的,我们修改mv命令由find的必要适当改变为$ {NEW}的$ {OLD}所有引用-printf功能命令提供,但为了做到这一点,我们有使用一些不应包含在最终输出中的任意参考点。所以一旦sed完成了所有需要做的事情,我们就指示它在传递它之前从保持缓冲区中消除其参考点。

,现在我们回到我的身边

read会收到类似如下的命令:

% mv /path2/$SRC/$OLD_DIR/$OLD_FILE /same/path_w/$NEW_DIR/$NEW_FILE \000 

将它read${msg}${sh_io}这可以随意检查功能之外。

很酷。

-Mike

0

我没有测试过这一点,但我认为这是你以后。

find . -name '[!.]*' -print | while read line; do nfile=`echo "$line" | sed 's/Namespace/Test/gI'`; mkdir -p "`dirname $nfile`"; cp -p "$line" "$nfile"; sed -i 's/Namespace/Test/gI' "$nfile"; done 
+0

这应该帮助我一个很好的方法..非常感谢。我会把它拆分一点,然后一块一块地做。 – Michael 2011-04-07 22:01:14