pipe then hyphen (stdin) 作为 for 循环的替代

pipe then hyphen (stdin) as an alternative to for loop

我写了几个 sed 和 awk 命令来提取一组与文件名关联的 ID。我想 运行 使用来自 id.txt

的这些文件名的一组命令

cat id.txt

14235.gz
41231.gz
41234.gz

我通常这样写for循环:

for i in $(cat id.txt);
do 
    command <options> $i
done

我以为我也可以cat id.txt | command <options> -

有没有办法将 cat、awk、sed 等的输出逐行传输到命令中?

使用 while 读取循环参见 Don't read lines wit for

while IFS= read -r line_in_text_file; do
 echo "$line_in_text_file"
done < id.txt

命令通常不会在标准输入中获取它们的文件名参数。使用 - 作为参数意味着从标准输入而不是命名文件读取文件内容,这并不意味着从标准输入中获取文件名。

您可以使用命令替换将文件的内容用作命令的所有文件名参数:

command <options> $(cat id.txt)

或者您可以使用 xargs

xargs command <options> < id.txt

Is there a way to pipe the output of cat, awk, sed, etc, line by line into a command?

复合命令可以放在管道中,语法不是很严格。通常:

awk 'some awk script' |
while IFS= read -r line; do
    echo "$line"
done |
sed 'some sed script'

我避免使用 while read 逐行读取输入 - 它非常慢。使用 awk 脚本和其他命令要快得多。

命令组可用于:

awk 'some awk script' |
{     # or '(', but there is no need for a subshell
      echo "header1,header2"
      # remove first line
      IFS= read -r first_line
      # ignore last line
      sed '$d'
} |
sed 'some sed script'

请记住,管道命令 运行 在子 shell 中,因此变量更改不会影响父 shell。

Bash 有进程替换扩展,让你 运行 在父 shell:

中有一个 while 循环
var=1
while IFS= read -r line; do
     if [[ "$line" == 2 ]]; then
        var=2
      fi
done <(
    seq 10 |
    sed '$d'
)
echo "$var"  # will output 2

xargs可以做到这一点

cat id.txt | xargs command

来自xargs帮助

$ xargs --help
Usage: xargs [OPTION]... COMMAND [INITIAL-ARGS]...
Run COMMAND with arguments INITIAL-ARGS and more arguments read from input.

Mandatory and optional arguments to long options are also
mandatory or optional for the corresponding short option.
  -0, --null                   items are separated by a null, not whitespace;
                                 disables quote and backslash processing and
                                 logical EOF processing
  -a, --arg-file=FILE          read arguments from FILE, not standard input
  -d, --delimiter=CHARACTER    items in input stream are separated by CHARACTER,
                                 not by whitespace; disables quote and backslash
...