使用进程替换来欺骗需要文件的程序,并以特定扩展名作为参数?

使用进程替换来欺骗需要文件的程序,并以特定扩展名作为参数?

这是我的用例:命令行实用程序可以接受带有命令行melt扩展名的文件名,然后打开它;.melt例如,这是一个正确的test_p.melt文件:

colour:blue
out=24

colour:red
out=48

...打开并播放melt test_p.melt.

现在,问题是.melt文件不支持注释,我希望它们支持注释(对于包含不可解析参数的任何行,您都会收到错误消息,包括带有 a 的行#)。所以这是一个带注释的test_c.melt文件:

# master comment here

colour:blue  # this is blue!
out=24

colour:red
out=48

直接打开它melt给出:

$ melt test_c.melt
Failed to load "# master comment here"
...

...并且没有显示蓝屏。

所以我想 - 好吧,我可以发表评论反正,然后使用 Bash 进程替换来过滤文件sed,并将其提供给melt应用程序。首先尝试用 进行测试cat,成功:

$ cat <(sed 's/#.*$//' test_c.melt)



colour:blue  
out=24

colour:red
out=48

... 看起来不错;,如果我尝试使用melt,它就会识破我的诡计:

$ melt <(sed 's/#.*$//' test_c.melt)
Failed to load "/dev/fd/62"
Failed to load "/dev/fd/62"

基本上,melt 获取了为进程替换提供的 Bash 管道的文件名 - 但不幸的是,它melt所做的是argv[i]直接处理;如果是文件,则需要.melt在文件名中看到扩展名;如果没有 - 过程失败。

所以我的问题是:在这种情况下,如何使用进程替换 - 因此管道的文件名具有特定的扩展名.melt?基本上,作为替换的结果,我想要一个管道文件名/dev/fd/62.melt,我认为它会通过。

注意:当然,我总是可以这样做:

sed 's/#.*$//' test_c.melt > test_c_temp.melt
melt test_c_temp.melt

...但首先,这里有两个命令 - 我想要一个单行管道;另一方面,它提出了另一个问题,即我考虑之后删除临时文件,这是我不喜欢的。

这是否可以通过 Bash 进程替换来实现——或者以某种方式通过标准 Linux 工具来实现?

答案1

一种可能性是指向melt显示文件修改副本的文件系统。保险丝是构建文件系统驱动程序的通用方法,由普通程序实现,不需要特权。有许多 FUSE 文件系统,并且其中之一很有可能可以帮助您。这个想法是提供一个挂载点,读取.melt文件时会读取“真实”文件,但注释会被过滤掉。

脚本文件系统看起来很有希望(但我从未使用过它)。像这样的东西应该有效:

mkdir ~/uncommented-melt
scriptfs -p "$HOME/bin/uncomment-melt;&*.melt" ~/work ~/uncommented-melt

包含您的文件~/work的树的根在哪里.melt~/bin/uncomment-melt

#!/bin/sh
sed 's/#.*$//' "$1"

然后,如果您有带有注释的文件~/work/test_c.melt,则可以运行melt ~/uncommented-melt/test_c.melt.

其他可能有用的 FUSE 文件系统:

  • 执行者— 让您可以使用 shell 脚本构建简单的 FUSE 驱动程序
  • AVFS或其他透明解压缩文件的 FUSE 文件系统:将注释的剥离定义为解压缩规则。

答案2

使用zshshell,您可以使用=(...)进程替换的形式(使用临时文件而不是/dev/fd/x文件和管道),您可以为其指定后缀:

(TMPSUFFIX=.melt; melt =(sed 's/#.*$//' test_c.melt))

有关详细信息,请参阅info zsh TMPSUFFIX(假设info页面已安装,您可能需要安装软件包zsh-doc)。

答案3

好吧,事实证明,在我的具体情况下,这些熔化脚本将被严格解释为命令行参数;所以只有一个sed所以仅仅OP中的并不能完全解决它(另外,还有其他东西,比如可以设置的配置文件)。所以这就是我最终所做的——可能可以在OP标题所涵盖的其他情况下提供灵感。

我最终决定使用这个:创建一个test.shmelt文件,它实际上是一个bash包含我注释的melt脚本代码的脚本;使该文件可执行chmod +x test.shmelt;然后编辑脚本后,将其运行为./test.shmelt.

运行时,它将test.melt在 中创建一个“已清理”的文件/tmp,并调用melt该文件。由于melt通常在程序结束后在终端中继续运行,因此通过 SIGINT 上的陷阱,可以在按下 Ctrl-C 时清除此临时文件(但不是必须)。

就这样,我还是有意见的;可以在源文件中快速编辑并运行melt并查看结果;并且还有一个“清理”了评论的文件,供我稍后使用。

这是代码test.shmelt

#!/bin/bash

# call with: ./test.shmelt


#TMLTFILE="test.melt" # for final export
TMLTFILE="${0%%.shmelt}.melt" # for final export

function finished() { echo ; } ; # use this when testing or montaging to keep exported (tmp) .melt file; uncomment the below to remove the tmp file
#~ function finished() { rm /tmp/"$TMLTFILE"; echo "fin1 $0" ; } ; trap finished SIGINT ;

echo 'Remember `pulseaudio --start` to hear audio with `melt`!'
pulseaudio --check
if [ $? -ne 0 ]; then
    pulseaudio --start
fi

DIRNAME=$(readlink -f $(dirname $0))
PROFILE="square_ntsc"


echo "
# the profile doesn't work from here;
# still has to be specified on command line
# but including it here so the path is saved for testing
#~ -profile
#~ ${PROFILE}

-video-track

  # can avoid pixmap: here, but that s the producer;
  # qimage: also works
  # NB it is NOT '-out 1645'; but 'out=1645'!!
  /media/myimg/%05d.bmp
  in=0
  out=1645
  #~ length=1645
  #~ loop=0
  #~ eof=stop

-audio-track

  /media/mysnd/snd.wav
  in=0
  out=1645
  #~ loop=0
  #~ eof=stop

#-consumer xml # doesn't work here

" | sed -e 's/#.*$//' -e 's/^[[:space:]]*//' -e '/^[[:space:]]*$/d' -e 's/[[:blank:]]*$//' > ${TMLTFILE}

# the sed: remove comments; remove indents; remove empty lines; remove spaces at end of line


# eof: one of: stop, loop, continue or pause (eof=stop)
# to loop, use `melt eof=loop ...` (but make sure first,
#  that the edit as a whole stops - use xml to check!)
# due to caching issues, preview pieces (up to ~300 frames) like this:
melt eof=loop -profile ${PROFILE} ${TMLTFILE} in=200 out=400

# must have profile here, for checking w/ -consumer xml (else segfault)
# this command may add additional producers to the xml!:
## melt -profile ${PROFILE} ${TMLTFILE} -consumer xml

# use this to generate xml if needed:
#melt -profile ${PROFILE} $(cat ${TMLTFILE} | tr '\n' ' ') -consumer xml

# if exited normally, cleanup:
finished

答案4

已经有一段时间了,但我会尝试以对我有用的方式回答标题问题。

这是相关的:为什么 BASH 进程替换不适用于某些命令?

所以我试图解决的具体问题是:

  1. 我有一个图像转换器;
  2. 它从[插入随机格式]转换为BMP/PNM/TGA等简单格式;
  3. 我想转换为 JPEG,因此需要将其与 ImageMagick 链接convert
  4. 我不想使用临时文件。

因此,不幸的是,该工具不喜欢输出到 stdout/fds/pipes,因为它从输出文件名的扩展名派生输出格式。那么如何欺骗它呢?

创建具有适当扩展名的符号链接/dev/fd/N并将其用作“临时文件”。

例子:

ln -s /dev/fd/4 temp.pnm
[TOOL] -i [INPUTFILE] -o temp.pnm 4>&1 | convert - [OUTPUT.JPG]

相关内容