2012-05-29 59 views
31

串在我使用xargs有时我并不需要明确地使用替换字符串:修改替换xargs的

find . -name "*.txt" | xargs rm -rf 

在其他情况下,我想以做这样的事情来指定替换字符串:

find . -name "*.txt" | xargs -I '{}' mv '{}' /foo/'{}'.bar 

上面的命令将当前目录下的所有文本文件移动到/foo,它会扩展bar追加到所有文件。

如果不是将一些文本附加到替换字符串中,我想修改该字符串以便可以在文件的名称和扩展名之间插入一些文本,我该怎么做?例如,假设我想像前面的例子那样做,但是文件应该被重命名/从<name>.txt移动到/foo/<name>.bar.txt(而不是/foo/<name>.txt.bar)。

更新:我设法找到一个解决方案:

find . -name "*.txt" | xargs -I{} \ 
    sh -c 'base=$(basename $1) ; name=${base%.*} ; ext=${base##*.} ; \ 
      mv "$1" "foo/${name}.bar.${ext}"' -- {} 

但我不知道是否有一个较短/更好的解决方案。

+1

没有,但我会用更多的引用'MV “$ 1” “富/ $ {名称}的.bar $ {转}”'你可以做'。 basename'就像这样:'base = $ {1 ## * /}'。您应该将解决方案作为答案发布并接受它。 –

+0

@DennisWilliamson感谢您的评论!我会再等一等,看看是否有人想出一些奇特的东西,否则我会自己回答这个问题。 – betabandido

+1

我想如果你的文件名是最后一行,你不需要命令行中的-I {}和{}。 (请注意,xargs的目的是为了分组,所以如果你不想在1个xargs的参数调用结束时需要多个东西,你需要“-l 1”(或者-Lar的某些版本的xargs)。 -I {}暗示-l 1,所以这就是为什么这也适用于此。) –

回答

12

在这样的情况下,while循环会更可读:

find . -name "*.txt" | while IFS= read -r pathname; do 
    base=$(basename "$pathname"); name=${base%.*}; ext=${base##*.} 
    mv "$pathname" "foo/${name}.bar.${ext}" 
done 

注意,你可能会发现在不同的子目录中的同名文件即可。你可以用mv覆盖重写吗?

+0

是的,我知道它有这个“问题”。其实我发布的例子是相当愚蠢的。我只是为了在我的问题中展示一个简单的例子,所以没有问题:) – betabandido

+1

要处理在其中包含换行符的文件名,请使用:find。 -name“* .txt”-print0 |同时读取-r -d''路径名; do ...' – Cem

+2

请注意,如果您尝试使用'--max-procs'来并行化xargs,则此(串行)方法将不起作用。 – g33kz0r

2

如果你可以使用除bash/sh以外的东西,并且这只是一个奇特的“mv”......你可以尝试历史悠久的“rename.pl”脚本。我一直在Linux和cygwin上使用它。

http://people.sc.fsu.edu/~jburkardt/pl_src/rename/rename.html

rename.pl 's/^(.*?)\.(.*)$/\1-new_stuff_here.\2/' list_of_files_or_glob 

您也可以使用“-p”参数rename.pl有它告诉你它会做,实际上并没有这样做。

我只是在我的c:/ bin(cygwin/windows环境)中尝试了以下内容。我使用了“-p”,因此它吐出了它会做的事情。这个例子只是分割基础和扩展,并在它们之间添加一个字符串。

perl c:/bin/rename.pl -p 's/^(.*?)\.(.*)$/\1-new_stuff_here.\2/' *.bat 

rename "here.bat" => "here-new_stuff_here.bat" 
rename "htmldecode.bat" => "htmldecode-new_stuff_here.bat" 
rename "htmlencode.bat" => "htmlencode-new_stuff_here.bat" 
rename "sdiff.bat" => "sdiff-new_stuff_here.bat" 
rename "widvars.bat" => "widvars-new_stuff_here.bat" 
+0

感谢您的回答!不过,“mv”示例仅仅是一个例子。我面临在很多其他情况下需要做类似的事情,所以我猜'rename.pl'不适用于这些情况。 – betabandido

+0

嗯,是的,没有;你可以很容易地修改rename.pl为* NOT *实际重命名一个文件,但是用它做一些其他的事情。正如你所看到的,使用“-p”参数,它根本不会重命名,而只是输出转换的结果。 您可以使用该脚本作为其他许多事情的基础,并且所需的参数是任意的perl代码,这是非常强大的。 但是,你当然欢迎。 –

9

如果你有GNU并行http://www.gnu.org/software/parallel/安装,你可以这样做:

find . -name "*.txt" | parallel 'ext="{/}" ; mv -- {} foo/{/.}.bar.${ext##*.}' 

你可以安装GNU并行只需:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel 
chmod 755 parallel 
cp parallel sem 

手表GNU并行的介绍视频,了解更多: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

+2

我还推荐GNU Parallel over'xargs',它功能更强大,更灵活。至于它的安装,我强烈建议使用你的发行版的包管理器(例如'sudo apt-get install parallel')或并行的推荐安装程序(按照http://git.savannah.gnu.org/cgit/parallel。 git/tree/README):'(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3)| bash' – MestreLion

+1

@MestreLion请不要推荐curl-pipe-to-shell反模式。什么是'pi.dk'?我为什么要信任这个域名? 'gnu.org'至少更值得信赖。但是,两个URL都不使用TLS,更重要的是,两者都不验证下载内容的加密签名。唯一推荐的解决方案是“apt-get”。 – blujay

+0

正如您所看到的,pi.dk/3会对加密签名进行验证,并在签名不匹配时停止。如果您觉得不舒服,直接将其直接输送到外壳,您可以将其保存到文件中,检查代码,然后运行它。 –

18

以下命令用xargs构造移动命令,替换'。'的第二个匹配项。 '.bar。',然后用bash执行命令,在mac OSX上工作。

ls *.txt | xargs -I {} echo mv {} foo/{} | sed 's/\./.bar./2' | bash 
+1

Dirtay!我喜欢它 – g33kz0r

+0

这是一个巧妙的把戏 – Zerodf

7

有可能做到这一点在一次通过(在GNU测试)避免使用临时变量赋值

find . -name "*.txt" | xargs -I{} sh -c 'mv "$1" "foo/$(basename ${1%.*}).new.${1##*.}"' -- {} 
+1

我喜欢用替换字符串作为shell的位置参数的方式,以便您可以执行替换和扩展。很酷。 – GL2014

0

通过上述@justaname答案启发的,该命令其中包含的Perl一个班轮将做到这一点:

find ./ -name \*.txt | perl -p -e 's/^(.*\/(.*)\.txt)$/mv $1 .\/foo\/$2.bar.txt/' | bash