gpt4 book ai didi

bash - 你如何为文件的每一行运行一个命令?

转载 作者:行者123 更新时间:2023-11-29 08:38:25 25 4
gpt4 key购买 nike

例如,现在我正在使用以下内容来更改我将其 Unix 路径写入文件的几个文件:

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

有没有更优雅、更安全的方法?

最佳答案

逐行读取文件并执行命令:4 个回答

这是因为不仅有 1 个答案...

  • shell命令行扩展
  • xargs专用工具
  • while read附上一些评论
  • while read -u使用专用 fd , 用于交互处理(示例)

  • 关于 OP 请求: 运行 chmod在文件 中列出的所有目标上, xargs是指示的工具。但是对于其他一些应用程序,少量文件等...
  • 读取整个文件作为命令行参数。

    如果您的文件不是太大,并且所有文件的名称都很好(没有空格或其他特殊字符,如引号),您可以使用 shell命令行扩展。简单地说:
    chmod 755 $(<file.txt)

    对于少量文件(行),此命令是较轻的一个。
  • xargs是正确的工具

    对于更大数量的文件,或几乎 任何 输入文件中的行数...

    对于许多 binutils 工具,例如 chown , chmod , rm , cp -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接受多个文件作为参数,但这与问题的标题相匹配。

    对于某些特殊情况,您甚至可以在 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..

    命令在哪里完成每行一次 .
  • while read和变种。

    正如 OP 所建议的那样 cat file.txt | while read in; do chmod 755 "$in"; done会工作,但有两个问题:
  • cat |是一个没用的 fork ,和
  • | while ... ;done ;done之后环境会消失的子shell .

  • 所以这可以更好地写:
    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

    用于避免奇怪文件名的问题。也许如果您遇到 UTF-8 的问题:
    while LANG=C IFS= read -r in ; do chmod 755 "$in";done <file.txt
  • 当您使用时 STDIN供阅读file.txt ,您的脚本无法交互(您不能再使用 STDIN)。
  • while read -u , 使用专用 fd .

    语法:while read ...;done <file.txt将重定向 STDINfile.txt .这意味着,在它们完成之前,您将无法处理流程。

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

    常量文件描述符是:0标准输入,1用于标准输出和 2对于 STDERR。您可以通过以下方式查看它们:
    ls -l /dev/fd/


    ls -l /proc/self/fd/

    从那里,您必须在 0 之间选择未使用的号码和 63 (更多,实际上取决于 sysctl super 用户工具)作为文件描述符:

    对于这个演示,我将使用 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 7<file.txt
    done

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

    注意:我使用了strike 版本,因为在使用并行进程执行许多 I/O 时,此语法可能很有用:
    mkfifo sshfifo
    exec 7> >(ssh -t user@host sh >sshfifo)
    exec 6<sshfifo
  • 关于bash - 你如何为文件的每一行运行一个命令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13939038/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com