【问题标题】:creating a temporary file in memory and using it as input file of a command在内存中创建一个临时文件并将其用作命令的输入文件
【发布时间】:2016-08-30 14:32:35
【问题描述】:

有一个命令 pdflatex,我想在我的 bash 脚本中使用它。它将文件名作为输入,它将在哪些内容上起作用。

现在我有一个如下所示的算法:

for stuff in list of stuff; do
  echo "${stuff}" > /tmp/tmpStuff
  pdflatex /tmp/tmpStuff
done 

现在这可以按预期工作。但我想我可以通过减少磁盘 I/O 来加快速度(因为 > 重定向写入文件)。我希望我可以写类似echo "$stuff" | pdflatex /tmp/tmpStuff 的东西,但 pdflatex 使用文件而不是标准输入作为其输入。有没有办法将"$stuff" 保存在内存中并将其作为一种文件传递给 pdflatex?

TLDR:如果我可以创建一个可以命名并保存在内存中的临时文件,我会很高兴。

【问题讨论】:

    标签: bash


    【解决方案1】:

    您可以为此使用进程替换:

    pdflatex <(echo "$stuff")
    

    来自 Bash 参考手册:

    3.5.6 Process Substitution

    支持命名管道的系统支持进程替换 (FIFO) 或命名打开文件的 /dev/fd 方法。它采用以下形式 的

    <(list)
    

    或

    >(list)
    

    进程列表在其输入或输出连接到 FIFO 或 /dev/fd 中的某个文件时运行。作为扩展的结果,此文件的名称作为参数传递给当前命令。如果 使用&gt;(list) 表单,写入文件将为列表提供输入。如果使用&lt;(list) 形式,则应读取作为参数传递的文件以获得列表的输出。请注意, 和左括号之间不能出现空格,否则该构造将被解释为重定向。

    我也想知道这里的字符串是否也可以:

    pdflatex <<< "$stuff"
    

    【讨论】:

    • 感谢您的回答,有没有办法将来自&lt;(echo "$stuff") 的文件命名为“临时”文件?我想知道,因为它似乎会导致 pdflatex 出现错误。
    • @Simonlbc 不,不是。如果你想要这个,你可能想看看mktemp。
    • 如果我用 mktemp 创建一个文件,该文件会在内存中吗?
    • @Simonlbc 您可以检查创建命名管道,如Pseudo files for temporary data 中所述。但是,使用进程替换似乎更好。
    • 感谢您的帮助。看来 echo "$stuff" | pdflatex -jobname outputPdfName 似乎毕竟可以工作。我也尝试了pdflatex &lt;&lt;&lt; "$stuff" -jobname outputPdfName,它似乎也可以正常工作,这很好。所以我猜&lt;&lt;&lt; "$stuff" 就像将字符串重定向到标准输入,对吗(我真的很好奇)?
    【解决方案2】:

    许多 shell 以及整个 Linux 都接受:

    echo "${stuff}" | pdflatex /dev/stdin

    【讨论】:

    • 感谢您的回答。我只是想知道为什么你会同时使用“|”符号,同时精确的 /dev/stdin 是有原因的吗?
    • stackoverflow.com/users/5432899/simonlbc: /dev/stdin 仅针对没有特定方式访问标准输入的程序添加...您的帖子暗示 pdflatext 就是其中之一。在简单的情况下,它也比过程替换更容易。有时,使用较长的名称也很有用,并且可以自我记录。仅供参考:/dev/std* 系列的另外两个也存在。
    【解决方案3】:

    没有一个提供的解决方案保证在所有可能的命令上都能工作。

    考虑下面的myCommand(而不是pdflatex):

    #!/bin/bash
    # myCommand
    test -f "$1" || { echo "error: Please provide a file"; exit 1; }
    echo "The file content is:"$(cat $1)
    

    尝试现有的解决方案:

    ./myCommand <(echo "abcdef")
    # error: Please provide a file
    
    echo "abcdef" | ./myCommand /dev/stdin
    # error: Please provide a file
    

    在我的 Ubuntu 我使用以下方法(使用 /dev/shm 内存文件存储):

    ramtmp="$(mktemp -p /dev/shm/)"
    echo "abcdef" > $ramtmp
    ./myCommand $ramtmp
    # The file content is:abcdef
    

    所以你的情况应该是:

    ramtmp="$(mktemp -p /dev/shm/)"
    for stuff in list of stuff; do
      echo "${stuff}" > $ramtmp
      pdflatex $ramtmp
    done 
    
    

    如果 pdflatex 执行是非阻塞的,请在循环内添加第一行。

    请注意,我不确定目前有多少发行版支持它。见Wikipedia article:

    基于 2.6 内核及更高版本的 Linux 发行版提供/dev/shm 作为RAM 磁盘形式的共享内存,更具体地说,作为全局可写目录( 存储在内存中的目录,系统的每个用户都可以在其中创建文件。 RedHat 和 Debian based 发行版都默认包含它。在内核配置文件中支持这种类型的 RAM 磁盘是完全可选的。[5]

    【讨论】:

    【解决方案4】:

    另一种解决方案是使用 ramdisk,即存在于 ram 中的文件系统。我总是在 ramdisk 上编译我的 LaTeX 来保存磁盘写入,并且出于同样的原因,我也将它用于构建在 Gentoo 上的 Portage 软件。

    创建一个的方法如下:

    Linux: sudo mkdir /mnt/ramdisk sudo mount -t tmpfs -o size=2G ramdisk /mnt/ramdisk

    随意将挂载点更改为任何内容。一个流行的选项是 /tmp/tmpfs 或 /tmp/ram

    macOS: diskutil erasevolume HFS+ "ramdisk" `hdiutil attach -nomount ram://$((sizeInGB*1024*2048))`

    这个例子将挂载在 /Volumes/ramdisk 上

    如果您希望使用 MB,请将结尾替换为 ram://$((sizeInMB*2048))

    【讨论】:

      猜你喜欢
      • 2014-03-10
      • 1970-01-01
      • 2018-04-29
      • 2022-12-11
      • 1970-01-01
      • 2014-06-15
      • 1970-01-01
      • 1970-01-01
      • 2016-02-20
      相关资源
      最近更新 更多