Ваш лучший выбор состоит в том, чтобы столкнуть Вашего собственного паука в Вашем предпочтительном языке сценариев, это могло быть сделано рекурсивно вроде:
// Pseudo-code to recursively check for broken links
// logging all errors centrally
function check_links($page)
{
$html = fetch_page($page);
if(!$html)
{
// Log page to failures log
...
}
else
{
// Find all html, img, etc links on page
$links = find_links_on_page($html);
foreach($links as $link)
{
check_links($link);
}
}
}
, Как только Ваш сайт получил определенный уровень внимания от Google, их , инструменты веб-мастера неоценимы в показе неработающих ссылок, с которыми могут столкнуться пользователи, но это является довольно реакционным - битые ссылки могут быть вокруг в течение нескольких недель, прежде чем Google индексирует их и зарегистрирует 404 в Вашей панели веб-мастера.
Запись Вашего собственного сценария как вышеупомянутое покажет Вам всем возможные неработающие ссылки, не имея необходимость ожидать Google (инструмент веб-мастера) или Ваши пользователи (404 в журналах доступа) для спотыкания через них.
If you're talking about an up-to-date timestamp on each line, that's something you'd probably want to do in your actual script (but see below for a nifty solution if you have no power to change it). If you just want a marker date on its own line before your script starts writing, I'd use:
( date 1>&2 ; myscript.sh ) 2>error.log
What you need is a trick to pipe stderr through another program that can add timestamps to each line. You could do this with a C program but there's a far more devious way using just bash
.
First, create a script which will add the timestamp to each line (called predate.sh
):
#!/bin/bash
while read line ; do
echo "$(date): ${line}"
done
For example:
( echo a ; sleep 5 ; echo b ; sleep 2 ; echo c ) | ./predate.sh
produces:
Fri Oct 2 12:31:39 WAST 2009: a
Fri Oct 2 12:31:44 WAST 2009: b
Fri Oct 2 12:31:46 WAST 2009: c
Then you need another trick that can swap stdout and stderr, this little monstrosity here:
( myscript.sh 3>&1 1>&2- 2>&3- )
Then it's simple to combine the two tricks by timestamping stdout
and redirecting it to your file:
( myscript.sh 3>&1 1>&2- 2>&3- ) | ./predate.sh >error.log
The following transcript shows this in action:
pax> cat predate.sh
#!/bin/bash
while read line ; do
echo "$(date): ${line}"
done
pax> cat tstdate.sh
#!/bin/bash
echo a to stderr then wait five seconds 1>&2
sleep 5
echo b to stderr then wait two seconds 1>&2
sleep 2
echo c to stderr 1>&2
echo d to stdout
pax> ( ( ./tstdate.sh ) 3>&1 1>&2- 2>&3- ) | ./predate.sh >error.log
d to stdout
pax> cat error.log
Fri Oct 2 12:49:40 WAST 2009: a to stderr then wait five seconds
Fri Oct 2 12:49:45 WAST 2009: b to stderr then wait two seconds
Fri Oct 2 12:49:47 WAST 2009: c to stderr
As already mentioned, predate.sh
will prefix each line with a timestamp and the tstdate.sh
is simply a test program to write to stdout
and stderr
with specific time gaps.
When you run the command, you actually get "d to stdout"
written to stderr (but that's your TTY device or whatever else stdout
may have been when you started). The timestamped stderr
lines are written to your desired file.
Пакет devscripts
в Debian / Ubuntu содержит сценарий под названием annotate-output
, который выполняет это (как для stdout, так и для stderr).
$ annotate-output make
21:41:21 I: Started make
21:41:21 O: gcc -Wall program.c
21:43:18 E: program.c: Couldn't compile, and took me ages to find out
21:43:19 E: collect2: ld returned 1 exit status
21:43:19 E: make: *** [all] Error 1
21:43:19 I: Finished with exitcode 2
Вот версия, которая использует цикл при чтении
, как pax , но не требует дополнительных файловых дескрипторов или отдельного сценария (хотя вы могли бы используйте один). Он использует подстановку процессов:
myscript.sh 2> >( while read line; do echo "$(date): ${line}"; done > error.log )
Использование pax predate.sh
:
myscript.sh 2> >( predate.sh > error.log )
#!/bin/bash
DEBUG=1
LOG=$HOME/script_${0##*/}_$(date +%Y.%m.%d-%H.%M.%S-%N).log
ERROR=$HOME/error.log
exec 2> $ERROR
exec 1> >(tee -ai $LOG)
if [ $DEBUG = 0 ] ; then
exec 4> >(xargs -i echo -e "[ debug ] {}")
else
exec 4> /dev/null
fi
# test
echo " debug sth " >&4
echo " log sth normal "
type -f this_is_error
echo " errot sth ..." >&2
echo " finish ..." >&2>&4
# close descriptor 4
exec 4>&-
Если вы хотите перенаправить обратно на стандартный вывод, я обнаружил, что вам нужно сделать это:
myscript.sh >> >( while read line; do echo "$(date): ${line}"; done )
Не знаю, зачем мне >
перед (
, поэтому <(
, но это то, что работает.