bash 来自管道和 wc -m 的脚本输入

bash script input from pipe and wc -m

我有这个代码:

#!/bin/bash
# ~/test.sh
if [[ -p /dev/stdin ]]; then
var="-"
else
var=""
fi
l=$(cat -n "$var" | wc -l)
c=$(cat -n "$var" | wc -m)
echo l=$l
echo c=$c

如果我运行:

$ ./test.sh file.txt
l=73
c=4909 # it is correct

但是如果

cat file.txt | ./test.sh
l=73
c=0    #why i have 0???

我不明白为什么我有 c=0

cat file.txt | cat -n - | wc -c 有效;那么我的代码有什么问题?

我做错了什么?

如何让它正常工作?

当您通过管道而不是打开文件时,不同之处在于 piped-in 或 stdin 是一个流(不返回开始)。

l=$(cat -n "$var" | wc -l)

使用整个流来计算行数。

达到时:

c=$(cat -n "$var" | wc -m)

stdin流已经被之前的行数消耗完了。它没有什么可数的了,因此返回 0.

幸运的是 wc 可以在同一个 运行 上完成这两个操作,然后您可以像这样读取结果值:

#!/usr/bin/env bash

var=${1--}
if [ -p /dev/stdin ]; then
  if [ $# -ge 1 ]; then
    printf %s\n 'Need either stdin or filename argument (not both)!' >&2
    exit 1
  fi
elif [ $# -ne 1 ]; then
  printf %s\n 'Need stdin or a single filename argument!' >&2
  exit 1
fi
read -r l c _ < <(wc -lm -- "$var")
printf 'l=%d\nc=%d\n' "$l" "$c"

第一个cat消耗标准输入直到文件结束;然后就无法在第二个 cat.

中再次读取相同的数据

通常的解决方法是使用临时文件;但是如果你只是想要来自 wc 的不同计数,运行 它一次并从它的输出中提取它们。

set -- $(cat -n "${@--}" | wc -l -m)
l=
c=

另请注意参数扩展 "${@--}" 如何根据脚本是否收到参数扩展为 "$@"-