¿Utilizar la sustitución de procesos para engañar a los programas que esperan archivos, con extensiones específicas como argumento?

¿Utilizar la sustitución de procesos para engañar a los programas que esperan archivos, con extensiones específicas como argumento?

Este es mi caso de uso: la utilidad de línea de comando meltpuede aceptar un nombre de archivo, con la extensión .melten la línea de comando, y abrirlo; Como ejemplo, este es un test_p.meltarchivo adecuado:

colour:blue
out=24

colour:red
out=48

... que se abre y juega con melt test_p.melt.

Ahora, la cuestión es que .meltlos archivos no admiten comentarios, lo cual me gustaría que hicieran (recibirá mensajes de error para cualquier línea que contenga un argumento no analizable, incluidos aquellos con, digamos, a #). Así que aquí hay un test_c.meltarchivo comentado:

# master comment here

colour:blue  # this is blue!
out=24

colour:red
out=48

Abrir esto meltdirectamente da:

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

... y no se muestra ninguna pantalla azul.

Entonces pensé: bueno, puedo poner comentarios.de todos modosy luego usar la sustitución del proceso Bash para filtrar el archivo sedy simplemente proporcionárselo a la meltaplicación. Primero, probé una prueba con cat, que tuvo éxito:

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



colour:blue  
out=24

colour:red
out=48

... se ve bien;pero, si lo intento con melt, se da cuenta de mi engaño:

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

Básicamente, melt obtuvo el nombre de archivo de la tubería que Bash proporcionó para la sustitución del proceso, pero desafortunadamente, lo que melthace es procesar argv[i]directamente; y en el caso de un archivo, debe ver una .meltextensión en el nombre del archivo; si no es así, el proceso falla.

Entonces mi pregunta es: ¿cómo podría usar la sustitución de procesos, para que el nombre de archivo de la tubería tenga una extensión específica, en este caso .melt? Básicamente, como resultado de la sustitución, me gustaría tener un nombre de archivo de tubería /dev/fd/62.melt, que creo que se aprobará.

NB: por supuesto, siempre puedo hacer:

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

... pero primero, hay dos comandos aquí, y me gustaría un canal de una sola línea; y por otro, me abre otro problema al pensar en eliminar archivos temporales después, lo cual no me gusta.

¿Es esto posible con la sustitución del proceso Bash, o de alguna manera con herramientas estándar de Linux?

Respuesta1

Una posibilidad sería señalar meltun sistema de archivos que muestre copias modificadas de archivos.FUSIBLEes una forma genérica de crear un controlador de sistema de archivos implementado por un programa normal y que no requiere privilegios. Haymuchos sistemas de archivos FUSE alrededor, y es muy probable que uno de ellos pueda ayudarle. La idea es proporcionar un punto de montaje donde al leer un .meltarchivo se lee el archivo "real" pero con los comentarios filtrados.

scriptfsParece prometedor (pero nunca lo he usado). Algo como esto debería funcionar:

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

¿Dónde ~/workestá la raíz del árbol que contiene tus .meltarchivos y ~/bin/uncomment-meltes?

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

Luego, si tiene un archivo ~/work/test_c.meltcon comentarios, puede ejecutar melt ~/uncommented-melt/test_c.melt.

Otros posibles sistemas de archivos FUSE útiles:

  • Ejecutar— le permite crear un controlador FUSE simple con scripts de shell
  • AVFSu otros sistemas de archivos FUSE que descomprimen archivos de forma transparente: defina la eliminación de comentarios como una regla de descompresión.

Respuesta2

Con el zshshell, puedes usar la =(...)forma de sustitución de procesos (que usa archivos temporales en lugar de /dev/fd/xarchivos y canalizaciones) para la cual puedes especificar un sufijo:

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

Consulte info zsh TMPSUFFIX(suponiendo que las infopáginas estén instaladas, es posible que necesite instalar un zsh-docpaquete) para obtener más detalles.

Respuesta3

Bien, resulta que en mi caso específico, este tipo de scripts de fusión deben interpretarse estrictamente como argumentos de línea de comandos; por lo que solo el seddel OP no es suficiente (además, hay otras cosas como perfiles que se pueden configurar). Así que esto es lo que terminé haciendo: probablemente pueda servir como inspiración en otros casos que cubriría el título del OP.

Finalmente me decidí por usar esto: crear un test.shmeltarchivo, que en realidad es un bashscript que contiene mi código de script comentado melt; hacer que este archivo sea ejecutable chmod +x test.shmelt; luego, después de editar el script, ejecútelo como ./test.shmelt.

Al ejecutarse, creará un test.meltarchivo "limpio" en /tmpy llamará melta este archivo en su lugar. Dado que meltnormalmente sigue ejecutándose en la terminal después del final de su programa, con una trampa en SIGINT este archivo temporal se puede limpiar cuando se presiona Ctrl-C (pero no es necesario).

De esa manera, todavía tengo comentarios; puede editar rápidamente el archivo fuente y ejecutar Melt y ver los resultados; y también tener un archivo "limpio" de comentarios, que puedo usar más adelante.

Aquí está el código de 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

Respuesta4

Ha pasado un tiempo, pero intentaré responder la pregunta del título de una manera que me haya resultado útil.

Esto está relacionado:¿Por qué la sustitución de procesos BASH no funciona con algunos comandos?

Entonces, el problema específico que estaba tratando de resolver era este:

  1. Tengo un conversor de imágenes;
  2. convierte de [insertar formato aleatorio] a formatos simples como BMP/PNM/TGA;
  3. Quiero convertir a JPEG, así que necesito encadenarlo con ImageMagick convert;
  4. No quiero utilizar archivos temporales.

Entonces, desafortunadamente, a la herramienta no le gusta generar salida a stdout/fds/pipes porque deriva el formato de salida de la extensión del nombre del archivo de salida. Entonces, ¿cómo engañarlo?

Cree un enlace simbólico con la extensión adecuada /dev/fd/Ny utilícelo como "archivo temporal".

Ejemplo:

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

información relacionada