我在一个文件夹中,在子文件夹中有一堆文件,我试图制作某种单行程,以便偶尔快速复制/粘贴。
内容(此处粘贴时间太长):http://pastebin.com/4aZCPbwT
我尝试过以下命令:
列出所有文件及其目录
find . -name '[!.]*'
将“Namespace”的所有实例替换为“Test:
find . -name '[!.]*' -print0 | sed 's/Namespace/Test/gI' | xargs -i -0 echo '{}'
我需要做的是:
替换上面的foldes名称,并将文件夹(包括文件)复制到另一个位置。创建文件夹(如果它们不存在)(它们很可能不会) - 但是,有一些我不需要的文件夹,例如./app,因为此文件夹存在。我可以使用-wholename'。/ app'。
当它们被复制时,我需要替换每个文件中的一些文本,与上面相同(带有测试的命名空间 - 也会在文件中出现并保存它们当然)。
我想象的是这样的事情:
-print -exec sed -i 's/Namespace/Test/gI' {} \;
这三件事可以在单行中完成吗?替换文件中的文本(Namespace< => Test),使用cp -p复制包含其目录的文件(不想写入文件夹),但是如上所述重命名每个目录/文件(Namespace< =>检验)。
非常感谢: - )
答案 0 :(得分: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
sed
版find
和find printf
来正确处理sed -z -e
和:;recursive regex test;t
和fork
来电。如果您无法使用这些功能,则可能会通过一些小的调整来复制功能。
这应该从头到尾做你想做的一切,而且很少。我与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
已存在的位置。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
使用各种优化技术来遍历您的文件系统树,并且不确定它是否会以安全的操作顺序返回我们需要的数据。这就是我们接下来的原因...... find
%directory-depth
对mv
的所有输出进行排序,以便最先处理与$ {SRC}关系最近的路径。这避免了将sed -ex :rcrs;srch|(save${sep}*til)${OLD}|\saved${SUBSTNEW}|;til ${OLD=0}
文件放入不存在的位置时可能出现的错误,并且最大限度地减少了递归循环的需要。 (事实上,你可能很难找到一个循环)%Path
sed
,以防它包含多个可能需要替换的$ {OLD}值。我想象的所有其他解决方案都涉及第二个sed
过程,虽然可能不需要短循环,但它确实会产生并分叉整个过程。stdout
在这里搜索$ {sed_sep},然后找到它,保存它和遇到的所有字符,直到找到$ {OLD},然后用$ {NEW替换它}。然后返回$ {sed_sep}并再次查找$ {OLD},以防它在字符串中出现多次。如果未找到,则将修改后的字符串打印到mv
(然后再次捕获)并结束循环。 mv
命令字符串的前半部分(当然需要包含$ {OLD})确实包含它,后半部分被更改为需要多次从sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
的目标路径中删除$ {OLD}名称。-exec
fork
来电没有第二个mv
。首先,正如我们所见,我们根据需要修改find
-printf
函数命令提供的sed
命令,以正确更改$的所有引用{OLD}到$ {NEW},但为了做到这一点,我们不得不使用一些不应包含在最终输出中的任意参考点。因此,一旦read
完成它需要做的所有事情,我们就会指示它在传递它之前从保持缓冲区中清除它的参考点。 现在我们重新回来
% mv /path2/$SRC/$OLD_DIR/$OLD_FILE /same/path_w/$NEW_DIR/$NEW_FILE \000
将收到如下命令:
read
${msg}
将其${sh_io}
改为{{1}}作为{{1}},可以在函数外部随意查看。
冷却。
-Mike
答案 1 :(得分: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