你如何运行一个文件的每一行命令?(How do you run a command for each

2019-10-29 12:28发布

例如,现在我用下面的方法修改了几个文件,它们的Unix的路径,我写了一个文件:

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

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

Answer 1:

按行读取文件行和执行命令:4个回答

这是因为,不仅是1的答案...

  1. shell命令行扩张
  2. xargs专用工具
  3. while read一些言论
  4. while read -u使用专用fd ,对于交互式处理(样品)

关于OP的要求: 运行chmod在文件中列出的所有目标xargs是指定的工具。 但是对于其他一些应用程序,文件量小,等...

  1. 阅读整个文件作为命令行参数。

    如果你的文件不是太大,所有文件都是很好命名 (不带空格或其他特殊字符像引号),你可以使用shell命令行扩张 。 只是:

     chmod 755 $(<file.txt) 

    对于少量的文件(线),这是命令的打火机之一。

  2. xargs是正确的工具

    对于金额较大的文件的,或者几乎任何数量的输入文件的行...

    对于许多binutils的工具,如chownchmodrmcp -t ...

     xargs 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) 

    测试与seq 1 5作为输入

    尝试这个:

     xargs -n 1 -I{} echo Blah {} blabla {}.. < <(seq 1 5) Blah 1 blabla 1.. Blah 2 blabla 2.. Blah 3 blabla 3.. Blah 4 blabla 4.. Blah 5 blabla 5.. 

    凡COMMANDE在每一行进行一次

  3. while read和变型。

    由于OP建议cat file.txt | while read in; do chmod 755 "$in"; done cat file.txt | while read in; do chmod 755 "$in"; done cat file.txt | while read in; do chmod 755 "$in"; done的工作,但有2个问题:

    • cat |无用的叉 ,和

    • | while ... ;done | while ... ;done将成为一个子shell,其中环境会后disapear ;done

    因此,这可以更好地写成:

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

    但,

    • 你可能会警告$IFSread标志:

       help read 
       read: read [-r] ... [-d delim] ... [name ...] ... Reads a single line from the standard input... The line is split into fields as with word splitting, and the first word is assigned to the first NAME, the second word to the second NAME, and so on... Only the characters found in $IFS are recognized as word delimiters. ... Options: ... -d delim continue until the first character of DELIM is read, rather than newline ... -r do not allow backslashes to escape any characters ... Exit Status: The return code is zero, unless end-of-file is encountered... 

      在某些情况下,您可能需要使用

       while IFS= read -r in;do chmod 755 "$in";done <file.txt 

      为了避免与似有文件名的问题。 也许,如果你encouter有问题的UTF-8

       while LANG=C IFS= read -r in ; do chmod 755 "$in";done <file.txt 
    • 当您使用STDIN读取file.txt ,你的脚本不能交互 (不能使用STDIN了)。

  4. while read -u ,使用专用fd

    语法: while read ...;done <file.txt会重定向STDINfile.txt 。 这意味着,你将无法处理的过程,直到他们完成。

    如果您打算创建交互式工具,你必须避免使用STDIN ,并使用一些替代文件描述符

    常数文件描述符0STDIN, 1STDOUT2STDERR。 你可以通过看他们:

     ls -l /dev/fd/ 

    要么

     ls -l /proc/self/fd/ 

    从那里,你必须选择未使用的编号,与063 (更多,其实,这取决于sysctl超级工具)的文件描述符

    在该演示中,我将使用FD 7

     exec 7<file.txt # Without spaces between `7` and `<`! ls -l /dev/fd/ 

    然后,你可以使用read -u 7是这样的:

     while read -u 7 filename;do ans=;while [ -z "$ans" ];do read -p "Process file '$filename' (y/n)? " -sn1 foo [ "$foo" ]&& [ -z "${foo/[yn]}" ]&& ans=$foo || echo '??' done if [ "$ans" = "y" ] ;then echo Yes echo "Processing '$filename'." else echo No fi done 

    要关闭fd/7

     exec 7<&- # This will close file descriptor 7. ls -l /dev/fd/ 


Answer 2:

是。

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

这样就可以避免一个cat的过程。

cat是几乎总是坏的目的,像这样。 你可以阅读更多关于猫的无用使用。



Answer 3:

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

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

bash的for循环

或者你的一个变种:

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


Answer 4:

如果你知道你没有输入任何空白:

xargs chmod 755 < file.txt

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

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


Answer 5:

如果你想在并行运行命令每个可以使用的线条GNU并行

parallel -a <your file> <program>

文件的每一行都将被传递到程序作为参数。 默认情况下, parallel运行许多线程作为您的CPU数量。 但你可以指定它-j



Answer 6:

我看到你所标记的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


Answer 7:

您还可以使用AWK,可以给你更多的灵活性来处理文件

awk '{ print "chmod 755 "$0"" | "/bin/sh"}' file.txt

如果你的文件有一个字段分隔符,如:

字段1,字段2,字段3

为了让只有你要做的第一场

awk -F, '{ print "chmod 755 "$1"" | "/bin/sh"}' file.txt

您可以检查GNU文档的更多信息https://www.gnu.org/software/gawk/manual/html_node/Very-Simple.html#Very-Simple



Answer 8:

该逻辑也适用于许多其他目标。 而如何读取/家庭/文件系统.sh_history每个用户的? 如果有他们的千?

#!/bin/ksh
last |head -10|awk '{print $1}'|
 while IFS= read -r line
 do
su - "$line" -c 'tail .sh_history'
 done

这里是脚本https://github.com/imvieira/SysAdmin_DevOps_Scripts/blob/master/get_and_run.sh



文章来源: How do you run a command for each line of a file?
标签: bash loops line