2012-12-18 25 views
89

例如,现在我用下面的方法修改了几个文件,它们的Unix的路径,我写了一个文件:如何为文件的每一行运行命令?

cat file.txt | while read in; do chmod 755 "$in"; done 

是否有一个更优雅,更安全的方法是什么?

回答

68

如果你的文件不是太大,所有文件以及命名为(不含空格或其他特殊字符像引号),你可以简单地说:

chmod 755 $(<file.txt) 

如果你有特殊字符和/或很多行file.txt

xargs -0 chmod 755 < <(tr \\n \\0 <file.txt) 

如果你的命令需要通过项1的确切时间运行:

xargs -0 -n 1 chmod 755 < <(tr \\n \\0 <file.txt) 

这是不需要这个的样品为chmod接受多个文件作为参数,但这场比赛问题的标题。

对于某些特殊的情况下,你甚至可以在命令generateds通过xargs定义文件参数的位置:

xargs -0 -I '{}' -n 1 myWrapper -arg1 -file='{}' wrapCmd < <(tr \\n \\0 <file.txt) 
+3

由于'xargs'是initialy build为了回答这种需求,一些特性,比如*尽可能在当前环境中*构建命令*尽可能少地调用'chmod',减少*叉*确保效率。 'while; do..done <$ file' implie为1个文件运行1个分支。 'xargs'可以以可靠的方式运行一千个文件。 –

+1

为什么第三个命令不能在makefile中工作?我得到了“意外令牌附近的语法错误'<'”,但直接从命令行执行。 –

+2

这似乎与Makefile特定的语法有关。您可以尝试反转命令行:'cat file.txt | tr \\ n \\ 0 | xargs -0 -n1 chmod 755' –

88

是的。

while read in; do chmod 755 "$in"; done < file.txt 

这样你就可以避开cat的过程。

cat对于这样的目的几乎总是不好的。你可以阅读更多关于Useless Use of Cat.

+0

避免*一个*'猫'是一个好主意,但在这种情况下** **指示的命令是'xargs' –

+0

该链接似乎不相关,也许网页的内容改变了?其余的答案是真棒,但:) :) – starbeamrainbowlabs

+0

@starbeamrainbowlabs是的。似乎页面已被移动。我已经重新关联,现在应该可以。谢谢:) –

9

,如果你有一个很好的选择(例如在目录中的所有.txt文件) 你可以这样做:

for i in *.txt; do chmod 755 "$i"; done 

bash for loop

或变体你的:

while read line; do chmod 755 "$line"; done <file.txt 
+0

不行的是,如果行中有空格,则输入被空格分隔,而不是按行分隔。 –

9

如果你知道你在输入中没有任何空格:

xargs chmod 755 < file.txt 

如果有可能在路径的空白,如果你有GNU xargs的:

tr '\n' '\0' < file.txt | xargs -0 chmod 755 
+0

我知道xargs,但(可惜)似乎不如bash内置的功能,如while和read可靠的解决方案。另外,我没有GNU xargs,但是我使用的是OS X,xargs在这里也有-0选项。感谢你的回答。 – hawk

+1

@hawk否:'xargs'健壮。这个工具是非常古老的,他的代码强烈*重访*。他的目标最初是为了在壳体限制(64kchar /线或其他)上建立线条。现在这个工具可以处理非常大的文件,并且可以减少fork到最终命令的数量。请参阅[我的回答](http://stackoverflow.com/a/13941223/1765658)和/或“man xargs”。 –

+0

@hawk更少的可靠的解决方案?如果它在Linux,Mac/BSD和Windows(是的,MSYSGIT的捆绑GNU xargs)中起作用,那么它就像它可靠一样。 –

2

我看到你所标记的bash,但Perl的也将是这样做的好方法:

perl -p -e '`chmod 755 $_`' file.txt 

你也可以申请一个正则表达式来确保你得到正确的文件,例如只处理.txt文件:

perl -p -e 'if(/\.txt$/) `chmod 755 $_`' file.txt 

要“预览”发生了什么事,只需更换用双引号反引号和前面加上print

perl -p -e 'if(/\.txt$/) print "chmod 755 $_"' file.txt 
+2

为什么使用反引号? Perl有一个['chmod'函数](http://perldoc.perl.org/functions/chmod.html) –

+0

我没有意识到这一点。感谢您指出:) –

+1

您希望'perl -lpe'chmod 0755,$ _'file.txt' - 使用'-l'作为“auto-chomp”功能 –

7

如果你想在每行平行运行命令,你可以使用GNU Parallel

parallel -a <your file> <program> 

文件的每一行都会作为参数传递给程序。默认情况下,parallel可以运行与CPU数量相同的线程数。但你可以指定它-j