Вы создаете каталог с именем из $3
, но создаете файл в текущем каталоге.
Чтобы создать файл в новом каталоге, просто перенаправьте на имя в этом каталоге:
mkdir "$3"
tr -dc 'A-Za-z0-9' </dev/urandom | head -c 255 >"$3/$(shuf -n 1 /usr/share/dict/french)"
Или, чтобы разделить вещи для удобства чтения:
dir=$3
mkdir -p -- "$dir" || exit 1
fname=$(shuf -n 1 /usr/share/dict/french)
tr -dc 'A-Za-z0-9' </dev/urandom | head -c 255 >"$dir/$fname"
Здесь я также убедился, что если $3
содержит пути с несуществующими подкаталогами, полный путь создается (путем добавления -p
к вызову mkdir
; что также делаетmkdir
не неудачным, если путь уже существует ). Я также добавляю к пути префикс--
на тот случай, если первый символ в $3
— это -
(, в противном случае это может привести к путанице mkdir
; --
сигнализирует об окончании параметров командной строки ). Я также выхожу с нулевым статусом выхода, отличным от -, если вызов mkdir
не удался.
Вы можете использовать эту 41-строчную программу TXR Lisp в качестве демона для мониторинга файла журнала и создания его версии с отметками времени в режиме реального времени.
TXR имеет очень мало зависимостей и небольшой объем памяти, но при этом обладает широкими возможностями.
Во-первых, демо:
Мы начинаем с состояния, в котором foo
и bar
не существуют. foo
будет файл журнала без штампов. bar
будет файл журнала с отметками:
$ rm -f foo bar
Мы запускаем программу stamp.tl
в фоновом режиме. Я не добавлял в него#!
(решетку )строку (упражнение для читателя ), поэтому мы используем txr
. -d
означает, что он перейдет в фоновый режим как демон :
$ txr stamp.tl -d foo bar
Хорошо, давайте начнем создавать контент вfoo
:
$ echo "first post" >> foo
$ cat foo
first post
Что происходит в bar
?
$ cat bar
2021-08-20 06:40:06 first post
Строка журнала появилась там с отметкой времени. Продолжай:
$ echo "second post" >> foo
$ cat bar
2021-08-20 06:40:06 first post
2021-08-20 06:40:17 second post
$ echo "third post" >> foo
$ cat bar
2021-08-20 06:40:06 first post
2021-08-20 06:40:17 second post
2021-08-20 06:40:24 third post
Теперь давайте попробуем кое-что. Предположим, что программное обеспечение, записывающее журнал foo
, ротирует журнал. foo
исчезает, а затем снова начинается с нулевой длины:
$ rm foo
$ echo "rotated" >> foo
$ cat foo
rotated
Что происходит с bar
?
$ cat bar
2021-08-20 06:40:06 first post
2021-08-20 06:40:17 second post
2021-08-20 06:40:24 third post
2021-08-20 06:40:49 rotated
Как видите, он отлично захватил строку rotated
.
Конечно, реальное решение состоит в том, чтобы исправить оригинальное программное обеспечение, которое ведет журнал без временных меток, но пока это может быть просто решением группы -.
Далее следует код. Программа имеет три варианта. В дополнение к приведенному выше -d
, который мы использовали,у него есть возможность перезаписать целевой файл (поведение по умолчанию — добавить )и возможность использовать полную буферизацию для записи (по умолчанию — использовать буферизацию строк ).
Обратите внимание, что программа не поддерживает ротацию выходного журнала, потому что она просто открывает файл и оставляет его открытым. Чтобы поддерживать внешнюю ротацию журналов, программе пришлось бы открывать и закрывать файл каждый раз, когда он записывает. Или же реализовать внутреннее вращение :после такого количества строк, закрыть файл, выполнить вращающееся переименование и повторно -открыть его.
;; Copyright 2021
;; Kaz Kylheku <kaz@kylheku.com>
;; Vancouver, Canada
;; All rights reserved.
;;
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions are met:
;;
;; 1. Redistributions of source code must retain the above copyright notice,
;; this list of conditions and the following disclaimer.
;;
;; 2. Redistributions in binary form must reproduce the above copyright notice,
;; this list of conditions and the following disclaimer in the documentation
;; and/or other materials provided with the distribution.
;;
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;; POSSIBILITY OF SUCH DAMAGE.
(defun stamp (infile outfile opts)
(when (and opts.daemonize
(not (daemon t nil))) ;; don't chdir
(put-line "failed to daemonize")
(exit nil))
(let* ((line-buf (if opts.fully-buffered "" "l"))
(write-mode (if opts.overwrite `w@{line-buf}` `a@{line-buf}`)))
(with-resources ((out (open-file outfile write-mode) (close-stream out))
(in (open-tail infile) (close-stream in)))
(whilet ((line (get-line in)))
(let ((stamp (time-string-local (time) "%Y-%m-%d %H:%M:%S")))
(put-line `@stamp @line` out))))))
(define-option-struct prog-opts nil
(w overwrite :bool
"Overwrite the output file instead of appending.")
(d daemonize :bool
"Run in the background as a daemon")
(f fully-buffered :bool
"Writes to the output file are flushed whenever\ \
an I/O buffer fills up. The default behavior is to\ \
flush after every line.")
(nil help :bool
"List this help text."))
(defvarl prog-name *load-path*)
(defun usage ()
(put-line "\nUsage:\n")
(put-line ` @{prog-name} [ options ] <infile> [ <outfile> ]`))
(let ((o (new prog-opts)))
o.(getopts *args*)
(when o.help
(usage)
o.(opthelp)
(exit nil))
(match-case o.out-args
((@infile @outfile) (stamp infile outfile o))
((@infile) (stamp infile `@infile.stamped` o))
(@else (usage) (exit nil))))