Prozesssubstitution verwenden, um Programme auszutricksen, die Dateien erwarten, mit bestimmten Erweiterungen als Argument?

Prozesssubstitution verwenden, um Programme auszutricksen, die Dateien erwarten, mit bestimmten Erweiterungen als Argument?

Hier ist mein Anwendungsfall: Das Befehlszeilenprogramm meltkann einen Dateinamen mit der Erweiterung .meltin der Befehlszeile akzeptieren und öffnen. Dies ist beispielsweise eine richtige test_p.meltDatei:

colour:blue
out=24

colour:red
out=48

... das sich öffnet und mit spielt melt test_p.melt.

Nun ist es so, dass .meltDateien keine Kommentare unterstützen, obwohl ich mir das wünschen würde (Sie erhalten Fehlermeldungen für jede Zeile, die ein nicht analysierbares Argument enthält, einschließlich der Zeilen mit beispielsweise einem #). Hier ist also eine kommentierte test_c.meltDatei:

# master comment here

colour:blue  # this is blue!
out=24

colour:red
out=48

Das meltdirekte Öffnen ergibt:

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

... und es wird kein Bluescreen angezeigt.

Also dachte ich - na ja, ich kann Kommentare einfügenTrotzdem, und verwenden Sie dann die Bash-Prozesssubstitution, um die Datei mit zu filtern sed, und stellen Sie diese einfach der meltAnwendung zur Verfügung. Zuerst habe ich einen Test mit versucht cat, der erfolgreich war:

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



colour:blue  
out=24

colour:red
out=48

... sieht gut aus;Aber, wenn ich das mit versuche melt, durchschaut es meine Trickserei:

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

Grundsätzlich hat Melt den Dateinamen aus der Pipe erhalten, die Bash für die Prozessersetzung bereitgestellt hat – leider melterfolgt die Verarbeitung jedoch argv[i]direkt; im Fall einer Datei muss eine .meltErweiterung im Dateinamen vorhanden sein, da der Prozess andernfalls fehlschlägt.

Meine Frage ist also: Wie kann ich Prozesssubstitution verwenden, damit der Dateiname der Pipe in diesem Fall eine bestimmte Erweiterung hat .melt? Im Grunde möchte ich als Ergebnis der Substitution einen Pipe-Dateinamen von /dev/fd/62.melt, was meiner Meinung nach funktionieren wird.

NB: Natürlich kann ich jederzeit Folgendes tun:

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

... aber erstens gibt es hier zwei Befehle – und ich möchte eine Einzeiler-Pipeline; und zweitens ergibt sich ein weiteres Problem, da ich anschließend darüber nachdenken muss, temporäre Dateien zu entfernen, was mir nicht gefällt.

Ist dies mit der Bash-Prozessersetzung möglich – oder irgendwie mit Standard-Linux-Tools?

Antwort1

Eine Möglichkeit wäre, meltauf ein Dateisystem zu verweisen, das geänderte Kopien von Dateien anzeigt.SICHERUNGist eine generische Methode zum Erstellen von Dateisystemtreibern, die von einem normalen Programm implementiert werden und keine Berechtigungen erfordern. Es gibtviele FUSE-Dateisysteme im Umlauf, und es besteht eine gute Chance, dass einer von ihnen Ihnen helfen kann. Die Idee besteht darin, einen Einhängepunkt bereitzustellen, an dem beim Lesen einer .meltDatei die „echte“ Datei gelesen wird, jedoch mit herausgefilterten Kommentaren.

SkriptFSsieht vielversprechend aus (aber ich habe es noch nie benutzt). So etwas sollte funktionieren:

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

wo ~/workist die Wurzel des Baumes, der Ihre .meltDateien enthält und ~/bin/uncomment-meltist

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

Wenn Sie dann eine Datei ~/work/test_c.meltmit Kommentaren haben, können Sie ausführen melt ~/uncommented-melt/test_c.melt.

Andere möglicherweise hilfreiche FUSE-Dateisysteme:

  • Ausführen— ermöglicht Ihnen den Aufbau eines einfachen FUSE-Treibers mit Shell-Skripten
  • AVFSoder andere FUSE-Dateisysteme, die Dateien transparent dekomprimieren: Definieren Sie das Entfernen von Kommentaren als Dekomprimierungsregel.

Antwort2

Mit der zshShell können Sie die =(...)Form der Prozessersetzung verwenden (die temporäre Dateien anstelle von /dev/fd/xDateien und Pipes verwendet), für die Sie ein Suffix angeben können:

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

Weitere Einzelheiten finden Sie unter info zsh TMPSUFFIX(vorausgesetzt, die infoSeiten sind installiert. Möglicherweise müssen Sie ein zsh-docPaket installieren).

Antwort3

Ok, es stellt sich heraus, dass diese Art von Melt-Skripten in meinem speziellen Fall streng als Befehlszeilenargumente zu interpretieren sind; also sedreicht das im OP allein nicht ganz aus (außerdem gibt es noch andere Dinge wie Profile, die festgelegt werden können). Hier ist also, was ich letztendlich gemacht habe – kann wahrscheinlich als Inspiration für andere Fälle dienen, die der Titel des OP abdeckt.

Ich habe mich letztendlich für folgende Methode entschieden: Erstellen Sie eine test.shmeltDatei, die eigentlich ein bashSkript ist, das meinen kommentierten meltSkriptcode enthält. Machen Sie diese Datei ausführbar chmod +x test.shmelt. Führen Sie das Skript nach der Bearbeitung als aus ./test.shmelt.

Beim Ausführen wird eine „bereinigte“ test.meltDatei in erstellt /tmpund meltstattdessen diese Datei aufgerufen. Da es meltnormalerweise nach dem Ende seines Programms im Terminal weiterläuft, kann diese temporäre Datei mit einem Trap auf SIGINT bereinigt werden, wenn Strg-C gedrückt wird (muss aber nicht).

Auf diese Weise habe ich immer noch Kommentare, kann schnell in der Quelldatei Änderungen vornehmen, Melt ausführen und die Ergebnisse sehen und habe außerdem eine von Kommentaren „bereinigte“ Datei, die ich später verwenden kann.

Hier ist der Code von 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

Antwort4

Es ist schon eine Weile her, aber ich werde versuchen, die Titelfrage auf eine Weise zu beantworten, die für mich hilfreich gewesen wäre.

Dies hängt damit zusammen:Warum funktioniert die BASH-Prozessersetzung bei einigen Befehlen nicht?

Das konkrete Problem, das ich zu lösen versuchte, war folgendes:

  1. Ich habe einen Bildkonverter;
  2. es konvertiert von [beliebiges Format einfügen] in einfache Formate wie BMP/PNM/TGA;
  3. Ich möchte in JPEG konvertieren und muss es daher mit ImageMagick verketten convert.
  4. Ich möchte keine temporären Dateien verwenden.

Leider gibt das Tool nicht gerne in stdout/fds/pipes aus, da es das Ausgabeformat aus der Dateinamenerweiterung der Ausgabedatei ableitet. Wie kann man es also austricksen?

Erstellen Sie einen symbolischen Link mit der entsprechenden Erweiterung /dev/fd/Nund verwenden Sie diesen als „temporäre Datei“.

Beispiel:

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

verwandte Informationen