Создайте символическую ссылку, указывающую на несуществующее местоположение внутри несуществующего каталога. Это имеет некоторые забавные последствия:
$ 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
EEXIST
(Файл существует). ENOENT
(Нет такого файла или каталога) ENOENT
. lstat, конечно, вернет информацию о символической ссылке. У этого есть два преимущества перед некоторыми другими предлагаемыми здесь решениями: (а) вам не нужна запущенная служба, отслеживающая создание каталога, и (б) имя не существует для большинства команд.
Вам придется попробовать, но я подозреваю, что какие бы правила перезаписи у вас ни были, они не используют lstat или другие команды без разыменования, что приводит к их сбою.
Вы можете выполнять их параллельно с помощью ... gnu parallel:
parallel "sh script.sh {} > {}.out" ::: *
Используйте 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
и будет работать с любой реализацией из сделать
.
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)
Вот однострочное решение
find ./ -name "*.fasta" -exec sh -c 'script.sh ${0} > ${0}.log' {} \;
Короче говоря, он находит нужные файлы и запускает на них ваш сценарий. Смысл использования sh -c
заключается в том, что символ перенаправления >
не интерпретируется напрямую.
Обычная оболочка , внутри сценария или функции:
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 символов каждую строку каждого входного файла, сохраняя результат, как вы ожидали.