Выполнение команд для нескольких файлов и присвоение каждому выходу уникального имени

Создайте символическую ссылку, указывающую на несуществующее местоположение внутри несуществующего каталога. Это имеет некоторые забавные последствия:

$ ln -s non-existent/foobar foo
$ ls -ln
total 0
lrwxrwxrwx 1 1000 1000 19 Okt  4 17:17 foo -> non-existent/foobar
$ mkdir foo
mkdir: cannot create directory ‘foo’: File exists
$ cat foo
cat: foo: No such file or directory
$ echo foo > foo
zsh: no such file or directory: foo
  1. mkdir, link и другие не работают с EEXIST (Файл существует).
  2. Попытка открыть путь для чтения, записи или добавления завершится неудачно с ENOENT (Нет такого файла или каталога)
  3. Использование stat (2) (не lstat (2) или stat (1) ) на локации также не работает с ENOENT . lstat, конечно, вернет информацию о символической ссылке.

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

Вам придется попробовать, но я подозреваю, что какие бы правила перезаписи у вас ни были, они не используют lstat или другие команды без разыменования, что приводит к их сбою.

2
24.03.2016, 00:51
5 ответов

Вы можете выполнять их параллельно с помощью ... gnu parallel:

parallel "sh script.sh {} > {}.out" ::: *
2
27.01.2020, 21:52

Используйте make !

Напишите файл с именем GNUmakefile с приведенным ниже содержимым, но там, где я поместил символ, вместо него поместите табуляцию (это должна быть табуляция, это не может быть пробелов).

all: $(filter-out %_output.fasta,$(wildcard *.fasta))

%_output.fasta: %.fasta
↦./script.sh $< >$@.tmp
↦mv $@.tmp $@

Теперь, чтобы восстановить все файлы, введите make . В качестве бонуса, если входной файл не изменился с момента последнего создания выходного файла, script.sh больше не запустится. Если вы активно изменяете script.sh и хотите регенерировать выходные файлы, добавьте script.sh после %. Fasta , таким образом файлы будут также может быть регенерирован, если сценарий был изменен.

Пояснения:

  • Первая строка определяет, что делать, когда вы запускаете make all . Поскольку это первая строка (первая target в терминологии make-файла), выполнение make без аргументов делает то же самое.
  • Часть после all: генерирует список имен файлов .fasta в текущем каталоге и удаляет те, которые называются _output.fasta .
  • Строка % _ output.fasta:%.fasta запускает правило , которое объясняет, как сгенерировать файл, имя которого заканчивается на _output.fasta ( target ) из соответствующего . файл fasta (зависимость ).
  • Следующие строки с отступом от табуляции - это команды, запускаемые для создания файлов.
  • Первая строка преобразует первую зависимость ( $ <) в файл .tmp .
  • Вторая строка переименовывает файл .tmp в целевой файл ( $ @ ). Причина этого двухэтапного процесса заключается в том, что если генерация прервана по какой-либо причине, это не оставит недопустимый целевой файл.

Примечание: я предполагаю, что вы используете Linux. В противном случае вам может потребоваться установить GNU make и запустить ее вместо команды по умолчанию make вашей системы, если вы хотите использовать приведенный выше код.

Если бы вы использовали другое расширение для выходных файлов, это немного упростило бы задачу.

all: $(patsubst %.fasta,%.out,$(wildcard *.fasta))

.SUFFIX: .out .fasta
.fast.out:
↦./script.sh $< >$@.tmp
↦mv $@.tmp $@

Если вы замените первую строку явным списком файлов ( all: foo.out bar.out ), тогда файл может быть вызван Makefile и будет работать с любой реализацией из сделать .

2
27.01.2020, 21:52
for f in *.fasta; do 
    sh script.sh "$f" > "${f%.*}_output.fasta"; 
done

# ${f%.*} strips a shortest match of `.*` from the end of "$f"
# (= strips .fasta)
3
27.01.2020, 21:52

Вот однострочное решение

find ./ -name "*.fasta" -exec sh -c 'script.sh ${0} > ${0}.log' {} \;

Короче говоря, он находит нужные файлы и запускает на них ваш сценарий. Смысл использования sh -c заключается в том, что символ перенаправления > не интерпретируется напрямую.

1
27.01.2020, 21:52

Обычная оболочка , внутри сценария или функции:

for file in "$@" ; do
  if true; do 
     # do some work which reads from stdin
     # and outputs to stdout
  fi > "${file}_output.fasta" < "$file"
done

Или более стандартным (но, возможно, утомительным)

for file in "$@" ; do
  output="${file}_output.fasta"
  some_program $file > $output
  another_program_appends $file >> $output
done

Вы также можете сделать что-то вроде этого с помощью awk:

$ awk '{ print substr($0,1,20) >> FILENAME "_output.fasta" }' *fasta

Сценарий awk выводит первые 20 символов каждую строку каждого входного файла, сохраняя результат, как вы ожидали.

1
27.01.2020, 21:52

Теги

Похожие вопросы