我在一个文件夹、子文件夹中有一堆文件,我试图制作某种单行代码,以便偶尔快速复制/粘贴。
内容如下(太长,无法粘贴到此处):http://pastebin.com/4aZCPbwT 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' {} \;
这三件事可以一口气完成吗?替换文件中的文本(命名空间 测试),使用 cp -p 复制文件及其目录(不想覆盖文件夹),但使用上述方法重命名每个目录/文件(命名空间 测试)。
多谢 :-)
Besides 描述了how煞费苦心地冗长下面,该方法也可能是独特的,因为它包含内置调试。除了编译并保存它认为应该执行的所有命令以执行请求的工作之外,它基本上不执行任何操作。
它还明确避免循环越多越好。除了sed
递归搜索多个匹配项pattern据我所知,没有其他递归。
最后,这完全是null
分隔 - 它不会在任何文件名中的任何字符上绊倒,除了null
。我认为你不应该拥有那个。
顺便说一句,这是REALLY快速地。看:
% _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
NOTE:以上function
可能需要GNU
的版本sed
and find
以妥善处理find printf
and sed -z -e
and :;recursive regex test;t
来电。如果您无法使用这些功能,则可以通过一些细微的调整来复制该功能。
这应该可以从头到尾完成您想要的所有事情,而且不会大惊小怪。我做到了fork
with sed
,但我也在练习一些sed
递归分支技术,这就是我来这里的原因。我想,这有点像在理发学校享受折扣理发。这是工作流程:
-
rm -rf ${UNNECESSARY}
- 我故意省略了任何可能删除或破坏任何类型数据的函数调用。你提到那个
./app
可能是不需要的。删除它或预先将其移动到其他地方,或者,您可以构建一个\( -path PATTERN -exec rm -rf \{\} \)
例行公事find
以编程方式执行此操作,但那是您的全部。
-
_mvnfind "${@}"
- 声明其参数并调用辅助函数。
${sh_io}
尤其重要的是它保存了函数的返回值。${sed_sep}
紧随其后;这是用于引用的任意字符串sed
函数中的递归。如果${sed_sep}
被设置为一个可能在您所操作的任何路径名或文件名中找到的值...好吧,只是不要让它这样。
-
mv -n $1 $2
- 整棵树从头开始移动。这样可以省去很多麻烦;相信我。您想要做的其余事情 - 重命名 - 只是文件系统元数据的问题。例如,如果您要将其从一个驱动器移动到另一个驱动器,或者跨越任何类型的文件系统边界,那么最好使用一个命令立即执行此操作。它也更安全。请注意
-noclobber
选项设置为mv
;正如所写,这个函数不会把${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:'
- After
find
找到我们需要的文件,它直接构建并打印出来(most)我们需要处理您的重命名命令。这%dir-depth
添加到每行的开头将有助于确保我们不会尝试使用尚未重命名的父对象来重命名树中的文件或目录。find
使用各种优化技术来遍历文件系统树,并且不确定它是否会以安全操作顺序返回我们需要的数据。这就是为什么我们接下来...
-
sort -general-numerical -zero-delimited
- 我们对所有的进行排序
find
的输出基于%directory-depth
以便首先处理与 ${SRC} 关系最近的路径。这可以避免可能出现的错误mv
将文件放入不存在的位置,并最大限度地减少递归循环的需要。 (事实上,你可能根本找不到循环)
-
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} 当然,确实包含它,并且后半部分会根据需要多次更改以擦除 ${OLD} 名称mv
的目标路径。
-
sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
- The two
-exec
这里的呼叫立即发生fork
。首先,正如我们所见,我们修改mv
命令由提供find
's -printf
必要时使用 function 命令来正确更改 ${OLD} 到 ${NEW} 的所有引用,但为了做到这一点,我们必须使用一些不应该包含在最终输出中的任意参考点。那么一次sed
完成了它需要做的所有事情后,我们指示它在传递它之前从保持缓冲区中清除它的参考点。
现在我们回来了
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)