将文件内容通过管道传递给程序的有效方法

Efficient way to pipe file contents to program

假设我们的命令 cmd 仅通过管道接收输入。给定一个文件名 file.txt,将其通过管道传输到命令中的最有效方法是什么? (我假设 cat file.txt | cmd 不是很有效..)

让我们用 1 GB 的 blob (dump.data) 做一个小测试:

使用 > 运算符比从 cat:

进行管道传输要快得多
$ time cat dump.data | cat >/dev/null

real    0m0.360s
user    0m0.000s
sys     0m0.608s

$ time cat <dump.data >/dev/null

real    0m0.158s
user    0m0.000s
sys     0m0.156s

理论上应该比 < 快一点的唯一方法是 cmd 接受文件名作为其参数并读取文件本身(因为不涉及 IPC - 只有一个进程处理数据)。然而,它在这个测试中没有任何区别:

$ time cat dump.data >/dev/null

real    0m0.158s
user    0m0.000s
sys     0m0.156s

下面是一些其他计时结果

fn="file.txt"
[[ -e $fn ]] && rm "$fn"

for i in {1..100} ; do
    echo "Line $i" >> "$fn"
done
arg='{print FNR, [=10=]}'
N=1000
func1() {
    for i in $(seq 1 $N) ; do
        awk "$arg" "$fn" > "$temp_file"
    done
}
func2() {
    for i in $(seq 1 $N) ; do
        cat "$fn" | awk "$arg" > "$temp_file" 
    done
}
func3() {
    for i in $(seq 1 $N) ; do
        while read line ; do
            printf "%s\n" "$line"
        done <"$fn" | awk "$arg" > "$temp_file"
    done
}
func4() {
    for i in $(seq 1 $N) ; do
        while read line ; do
            echo "$line"
        done <"$fn" | awk "$arg" > "$temp_file"
    done
}

func5() {
    for i in $(seq 1 $N) ; do
        readarray -t a <"$fn"
        printf "%s\n" "${a[@]}" | awk "$arg" > "$temp_file"
    done
}

func6() {
    for i in $(seq 1 $N) ; do
        awk "$arg" > "$temp_file" <"$fn"
    done
}

time_it() {
    temp_file="tmp_out.txt"
    name="func"
    { time "$name"; } |& awk -vfn="$name" 'NR==2 {print fn, substr( , 3, length( ) - 3 ) }'
}

for i in {1..6} ; do
    time_it $i
done

我的 Ubuntu 笔记本电脑上单个 运行 的输出是:

func1 1.558
func2 2.273
func3 1.704
func4 1.427
func5 2.188
func6 1.576

请注意,func1仅用于比较。它不使用管道输入。我们看到对于这个特定的 运行、func4func6 大约和 func1..

一样快