Использовать подстановку процессов для обмана программ, ожидающих файлы с определенными расширениями в качестве аргумента?

Использовать подстановку процессов для обмана программ, ожидающих файлы с определенными расширениями в качестве аргумента?

Вот мой вариант использования: утилита командной строки 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считывает «реальный» файл, но с отфильтрованными комментариями.

ScriptFSвыглядит многообещающе (но я никогда этим не пользовался). Что-то вроде этого должно работать:

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:

  • Execfuse— позволяет создать простой драйвер FUSE с помощью скриптов оболочки
  • АВФСили другие файловые системы FUSE, которые прозрачно распаковывают файлы: определяют удаление комментариев как правило распаковки.

решение2

С помощью zshоболочки вы можете использовать =(...)форму подстановки процессов (которая использует временные файлы вместо /dev/fd/xфайлов и каналов), для которой вы можете указать суффикс:

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

Подробную информацию см . в разделе info zsh TMPSUFFIX(если infoстраницы установлены, возможно, вам потребуется установить пакет).zsh-doc

решение3

Хорошо, оказывается, что в моем конкретном случае такие сценарии melt должны интерпретироваться строго как аргументы командной строки; поэтому одного 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]

Связанный контент