执行内联修改文件并使其接受 stdin/stdout 的命令

执行内联修改文件并使其接受 stdin/stdout 的命令

假设我有一个命令foo接受一个文件并在该文件中执行一些转换(类似于sed -i)。假设此命令不接受经典的“从标准输入读取、转换、写入标准输出”选项。

有没有某种方法可以“转换”此命令,以便它允许使用 stdin/stdout 工作流程?

我能想到的第一件事是编写某种使用临时文件的包装器。但我想知道是否有某种标准化的“元工具”可以做到这一点(或一些 bash 技巧)。

答案1

虽然有点俗气,但是:

my_temp_file=$(mktemp)
cat > "$my_temp_file"
foo "$my_temp_file"
cat "$my_temp_file"
rm -f "$my_temp_file"

如果不明显的话,这个

  • 读取标准输入并将其写入文件,
  • foo在临时文件上调用您的程序,
  • 读取临时文件并将其写入标准输出,并且
  • 删除临时文件。

如果要处理的数据太大而无法放入/tmp.您可以通过使用--tmpdir选项将mktemp 临时文件放入具有更多可用空间的文件系统中来稍微缓解这一问题。

如今,连接命令&&非常流行。这么说可能更有意义

my_temp_file=$(mktemp) && {
    cat > "$my_temp_file"  && {
        foo "$my_temp_file"
        cat "$my_temp_file"
    }
    rm -f "$my_temp_file"
}

因为

  • 如果mktemp失败,你没有临时文件,你也无能为力,
  • 如果cat > "$my_temp_file"失败,则说明您尚未捕获输入,因此您无能为力(除非您仍然想删除临时文件)

如果退出状态foo对您很重要,请适当处理。

trap 可以选择通过设置一个来执行此操作,rm即使事情出现问题也可以使其更加防弹。

答案2

就像 G-Man 的答案一样,但封装在一个函数中:

foo_stream() { 
    local t=$(mktemp) && 
    cat - >| "$t" && 
    foo "$t" && 
    cat "$t" && 
    rm "$t"
}

因此,如果 foo 是:(foo() { sed -i 's/.*/& & &/' "$1"; }将每行“三倍”),那么我们可以按照自己喜欢的方式在管道中使用 foo_stream :

$ seq 10 | foo_stream | tac
10 10 10
9 9 9
8 8 8
7 7 7
6 6 6
5 5 5
4 4 4
3 3 3
2 2 2
1 1 1

注意:我用来set -o noclobber避免意外覆盖现有文件,>|重定向可以覆盖它。

答案3

如果你有控制权foo它不编辑到位但你可以提供一个输入文件输出文件:

foo() { sed 's/.*/& & &/' "$1" > "$2"; }

然后您可以使用进程替换来表示“输入管道”和“输出管道”。

$ foo <(seq 10) >(tac)
10 10 10
9 9 9
8 8 8
7 7 7
6 6 6
5 5 5
4 4 4
3 3 3
2 2 2
1 1 1

相关内容