简体   繁体   English

在bash脚本中逐行阅读

[英]Read line by line in bash script

I want to do the following, read line by line of a file and use the value per line as params 我想要执行以下操作,逐行读取文件并使用每行的值作为参数

FILE="cat test"
echo "$FILE" | \
while read CMD; do
echo $CMD
done

but when I do the echo $CMD, it just returns cat :S 但当我做echo $ CMD时,它只返回cat:S

FILE=test

while read CMD; do
    echo "$CMD"
done < "$FILE"

A redirection with < "$FILE" has a few advantages over cat "$FILE" | while ... 使用< "$FILE"重定向比cat "$FILE" | while ...具有一些优势 cat "$FILE" | while ... . cat "$FILE" | while ... It avoids a useless use of cat , saving an unnecessary child process. 它避免了无用的猫 ,节省了不必要的子进程。 It also avoids a common pitfall where the loop runs in a subshell. 它还避免了循环在子shell中运行的常见缺陷。 In bash, commands in a | 在bash中,命令在| pipeline run in subshells, which means variable assignments are lost after the loop ends. 管道在子壳中运行,这意味着在循环结束后变量分配将丢失。 Redirection with < doesn't have that problem, so you could use $CMD after the loop or modify other variables inside the loop. 使用<重定向没有那个问题,所以你可以在循环后使用$CMD或修改循环内的其他变量。 It also, again, avoids unnecessary child processes. 它还可以避免不必要的子进程。

There are some additional improvements that could be made: 可以进行一些额外的改进:

  • Add IFS= so that read won't trim leading and trailing whitespace from each line. 添加IFS=以便read不会修剪每行的前导和尾随空格。
  • Add -r to read to prevent from backslashes from being interpreted as escape sequences. 添加-r以读取以防止反斜杠被解释为转义序列。
  • Lower case CMD and FILE . 小写CMDFILE The bash convention is only environmental and internal shell variables are uppercase. bash约定只是环境和内部shell变量是大写的。
  • Use printf in place of echo which is safer if $cmd is a string like -n , which echo would interpret as a flag. 如果$cmd是一个像-n这样的字符串,那么使用printf代替echo更安全, echo会将其解释为一个标志。
file=test

while IFS= read -r cmd; do
    printf '%s\n' "$cmd"
done < "$file"

What you have is piping the text "cat test" into the loop. 你所拥有的是将文本"cat test"传递到循环中。

You just want: 你只想要:

cat test | \
while read CMD; do
    echo $CMD
done

xargs is the most flexible solution for splitting output into command arguments. xargs是将输出拆分为命令参数的最灵活的解决方案。

It is also very human readable and easy to use due to its simple parameterisation. 由于其简单的参数化,它也非常易读且易于使用。

Format is xargs -n $NUMLINES mycommand . 格式为xargs -n $NUMLINES mycommand

For example, to echo each individual line in a file /tmp/tmp.txt you'd do: 例如,要echo文件/tmp/tmp.txt中的每一行,您需要执行以下操作:

cat /tmp/tmp.txt | xargs -n 1 echo

Or to diff each successive pair of files listed as lines in a file of the above name you'd do: diff每对连续列为你会做上述名称的文件行的文件:

cat /tmp/tmp.txt | xargs -n 2 diff

The -n 2 instructs xargs to consume and pass as separate arguments two lines of what you've piped into it at a time. -n 2指示xargs使用并作为单独的参数传递两行你一次传入它的内容。

You can tailor xargs to split on delimiters besides carriage return/newline. 除了回车符/换行符之外,您还可以定制xargs以拆分分隔符。

Use man xargs and google to find out more about the power of this versatile utility. 使用man xargs和google可以了解有关此多功能实用程序功能的更多信息。

Do you mean to do: 你的意思是:

cat test | \
while read CMD; do
echo $CMD
done

If you want to use each of the lines of the file as command-line params for your application you can use the xargs command. 如果要将文件的每一行用作应用程序的命令行参数,可以使用xargs命令。

xargs -a <params_file> <command>

A params file with: 一个params文件:

a
b
c
d

and the file tr.py: 和文件tr.py:

import sys
print sys.argv

The execution of 执行

xargs -a params ./tr.py

gives the result: 给出结果:

['./tr.py', 'a', 'b', 'c', 'd']
while read CMD; do
    echo $CMD
done  << EOF
data line 1
data line 2
..
EOF

The correct version of your script is as follows; 脚本的正确版本如下;

FILE="cat test"
$FILE | \
while read CMD; do
echo $CMD
done

However this kind of indirection --putting your command in a variable named FILE-- is unnecessary. 然而,这种间接性 - 在名为FILE--的变量中输入命令是不必要的。 Use one of the solutions already provided. 使用已提供的解决方案之一。 I just wanted to point out your mistake. 我只想指出你的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM