. Вы можете использовать Командная строка ssh
для запуска сервера SOCKS, который будет подключаться к указанному вами хосту:
ssh -D 2001 user@host.com
Это запустит сервер SOCKS на порту 2001, который будет направлять запросы на host.com. Они называют эту функцию «динамической переадресацией портов на уровне приложения».
Еще:
Это возможно, но, как говорили другие, самый безопасный вариант - это создание нового файла, а затем перемещение этого файла для перезаписи оригинала.
Приведенный ниже метод загружает строки в BASH, поэтому, в зависимости от количества строк из tail
, это повлияет на использование памяти локальной оболочкой для хранения содержимого строк журнала.
Ниже также удаляются пустые строки, если они существуют в конце файла журнала (из-за поведения BASH, оценивающего «$ (tail -1000 test.log)»
), поэтому не дает действительно 100% точное усечение во всех сценариях, но в зависимости от вашей ситуации может быть достаточно.
$ wc -l myscript.log
475494 myscript.log
$ echo "$(tail -1000 myscript.log)" > myscript.log
$ wc -l myscript.log
1000 myscript.log
Утилита sponge
предназначена именно для этого случая. Если он у вас установлен, то ваши две строчки могут быть записаны:
tail -n 1000 myscript.log | sponge myscript.log
Обычно чтение из файла одновременно с записью в него ненадежно. sponge
решает эту проблему, не записывая в myscript.log
, пока tail
не закончит его чтение и не завершит конвейер.
Чтобы установить sponge
в системе, подобной Debian:
apt-get install moreutils
Чтобы установить sponge
в системе RHEL / CentOS, добавьте репозиторий EPEL, а затем выполните:
yum install moreutils
Из man sponge
:
sponge
считывает стандартный ввод и записывает его в указанный файл. В отличие от перенаправления оболочки,sponge
поглощает весь свой ввод перед записью выходного файла. Это позволяет создавать конвейеры, которые читают и записывают в один и тот же файл.
определенно "хвост + мв" намного лучше! Но для gnu sed мы можем попробовать
sed -i -e :a -e '$q;N;101,$D;ba' log
Для записи, с помощью ed
вы можете сделать что-то вроде
ed -s infile <<\IN
0r !tail -n 1000 infile
+1,$d
,p
q
IN
Это открывает infile
и r
вводит вывод tail -n 1000 infile
(т.е. вставляет этот вывод перед 1-й строкой), а затем удаляет то, что изначально было 1-й строкой, до конца файла. Замените , p
на w
, чтобы отредактировать файл на месте.
Имейте в виду, что решения ed
не подходят для больших файлов.
В сценарии вы можете реализовать логику ротации журналов. Выполните всю регистрацию с помощью функции:
log()
{
...
}
Эта функция, во-первых, делает что-то вроде:
printf "%s\n" "$*" >> logfile
затем проверяет размер файла или каким-то образом решает, что файл требует поворота. В этот момент файл logfile.1
, если он существует, удаляется, файл logfile.0
, если он существует, переименовывается в logfile.1
] и файл журнала
переименован в файл журнала.0
.
Решение о вращении может быть основано на счетчике, который хранится в самом скрипте. Когда он достигает 1000, он сбрасывается до нуля.
Если всегда требуется строгое усечение до 1000 строк, сценарий может подсчитать количество строк в файле журнала при запуске и соответствующим образом инициализировать счетчик (или, если счетчик уже соответствует или превышает 1000, выполнить ротацию немедленно ).
Или вы можете получить размер, например, с помощью wc -c logfile
, и выполнить ротацию на основе превышения определенного размера.Таким образом, файл никогда не нужно сканировать для определения состояния.
Я использовал вместо mv
команду cp
, чтобы вы могли иметь некоторые файлы журналов прямо там, где программное обеспечение это работает. Возможно, в другом домашнем каталоге пользователя или в каталоге приложения и иметь все журналы в одном месте в виде жестких ссылок. Если вы используете команду mv
, вы потеряете жесткую ссылку. Если вместо этого вы используете команду cp
, вы сохраните эту жесткую ссылку.
мой код выглядит примерно так:
TMP_FILE="$(mktemp "${TMPFILENAME}.XXX")"
for FILE in "${LOGFILE_DIR}"/* ; do
tail -n $MAXLINES "${FILE}" > "${TMP_FILE}"
if [ $(ls -g "${TMP_FILE}" | awk '{print $4}') -lt $(ls -g "${FILE}" | awk '{print $4}') ] ; then
cp "${TMP_FILE}" "${FILE}"
fi
done
Итак, если файлы находятся в одной и той же файловой системе, вы также можете предоставить пользователям разные права, а в ${LOGFILE_DIR}
вы изменяете длину, например Я делаю.
Если это команда mv
, вы теряете жесткую связь между файлами, и поэтому ваш второй файл больше не связан с первым - возможно, он находится где-то еще.
Если в другом месте вы не позволяете кому-либо стирать файл, ваши журналы остаются вместе и хорошо контролируются с помощью вашего собственного скрипта.
logrotate
может быть лучше. Но я доволен этим решением.
Не беспокойтесь о «», но в моем случае есть несколько файлов с пробелами и другими специальными буквами, и если я не использую «» или {}, все работает плохо. .
Например, существует каталог, в котором старые файлы автоматически заархивируются в OLDFILE.zip
, и все, что заархивировано, также указано в файле .zip_log
, поэтому .zip_log
также находится в этом каталоге, но в LOGFILE_DIR
у меня есть:
ln .zip_log "${LOGFILE_DIR}/USER_ZIP_log"
аналогичный файл, так как это жесткая ссылка.
Если другой процесс обновляет файл журнала и вы хотите избежать вмешательства в него, лучше всего сохранить второй файл. Второй файл (, назовем его "архивным файлом" ), будет содержать последние n
записанные строки.
Чтобы сделать это максимально аккуратно, сначала переместите существующий файл журнала во временное расположение. Затем объедините его с ранее сохраненным архивным файлом и сохраните до n
строк.
Что касается процесса, который ведет журнал, он должен просто запустить новый файл в следующий раз, когда он записывает сообщение журнала.
#!/bin/bash
log_dir=/path/to/my/logs
log_filename=my_file.log
lines_to_keep=1000
archive_filename="${log_filename}.001"
work_dir="$(mktemp -d -p "$logdir")" && \
touch "$log_dir/$archive_filename" && \
touch "$log_dir/$log_filename" && \
mv "$log_dir/$archive_filename" "$work_dir/" && \
mv "$log_dir/$log_filename" "$work_dir/" && \
cat "$work_dir/$archive_filename" "$work_dir/$log_filename" | \
tail -n $lines_to_keep > "$log_dir/$archive_filename" && \
rm "$work_dir/$archive_filename" && \
rm "$work_dir/$log_filename" && \
rmdir "$work_dir"