у меня есть файл журнала с содержимым внутри. то есть имя файла convert.20231010.log.
Содержимое внутри файла, как показано ниже.
2024-05-17 00:14:02.447 Success ABCXYZ15 on hard disk
2024-05-17 00:14:02.447 Fail at /home/category1/sub1/ABCXYZ01 00054 is not found
2024-05-17 00:14:02.447 Success ABCXYZ16 00030 on hard disk
2024-05-17 00:14:02.447 Fail at /home/category1/sub2/ABCXYZ02 is not found
2024-05-17 00:14:02.447 Success ABCXYZ17 000110 on hard disk
Я хочу проверить файл и поработать над этим.
а) найти в журнале строку с условием «Сбой» и «не найден», получить путь и имя файла.
grep -E 'Fail.*is not found' convert.20231010.log
нашел 2 строки с правильным состоянием
2024-05-17 00:14:02.447 Fail at /home/category1/sub1/ABCXYZ01 00054 is not found
2024-05-17 00:14:02.447 Fail at /home/category1/sub2/ABCXYZ02 is not found
б) выберите файл по пути и проверьте содержимое файла
путь и имя файла будут выбраны из категории 2 на основе основания на шаге a.
/home/category2/sub1/ABCXYZ01 00054
/home/category2/sub2/ABCXYZ02
в) переместить файл, если содержимое хорошее
На основе шага b прочитайте файлы содержимого «ABCXYZ01 00054» и «ABCXYZ02». Если содержание хорошее, переместите файл в категорию3. Проверка содержимого внутри файла — «CARD», если она действительно имеет значение, то файл в порядке. Если «CARD» пусто или пусто, не перемещайте этот файл.
ID=ABCXYZ01 00054
NAME=JOIN
DEPT=ACC
CARD=1234
LOC=NY
ID=ABCXYZ02
NAME=CINDY
DEPT=LOG
CARD=6789
LOC=LA
mv -f '/home/category2/sub1/ABCXYZ01 00054' '/home/category3/sub1/'
mv -f '/home/category2/sub2/ABCXYZ02' '/home/category3/sub2/'
г) удалить строку в файле журнала
этот удалит 2 строки в файле журнала на шаге a
sed -i '/Fail.*is not found/d' convert.20231010.log
Как я могу использовать оболочку bash в Linux и записать новый журнал от шага от a до d? Я не знаком с оболочкой, благодарен за вашу помощь.
#!/bin/bash
MYSELF=$0
MYNAME=`echo $0 | gawk '{print substr($0, match($0, /[^/]+$/))}'`
MYNAME_NOEXT=`echo "$MYNAME" | gawk '{print gensub(/\.[^\.]*$/, "", "g")}'`
MYPATH=`echo $0 | gawk '{print substr($0, 1, match($0, /[^/]+$/) - 1)}'`
if [ $MYPATH == "./" ]; then MYPATH = "`pwd`/"; fi
cd $MYPATH
logfile = "/home/category4/logs/"$MYNAME_NOEXT.`date +"%Y%m%d"`.log
(
if [ `ps -ef | grep -i "$MYNAME" | wc -l` -gt 4 ]
then
echo $(date +%Y-%m-%d) $(date +%H:%M:%S)" - Script '$MYNAME' is running. Force exit as re-entry not allowed."
exit
fi
filename = "convert".`date +"%Y%m%d"`.log
while read -r line; do
linetext = "$line"
echo "single line in log - $linetext"
done
echo $(date) " - Script '$MYNAME' is ended normally."
) >> $logfile 2>&1
Итак, я сказал, что не знаком с оболочкой, поэтому и спрашиваю. Если не можете, пожалуйста, исключите это. Большое спасибо.
Прекратите использовать обратные кавычки. Используйте синтаксис $() для замены команд.





Непроверено, поскольку у меня нет и я не хочу создавать структуру каталогов, которая потребуется вашему сценарию и входному файлу для тестирования:
Использование GNU awk для не-POSIX расширений третьего аргумента для match() плюс nextfile, поскольку ОП теперь сообщил нам, что их файл журнала огромен:
#!/usr/bin/env bash
while IFS= read -r file; do
[[ -f "$file" ]] &&
>&2 echo mv -f -- "$file" '/home/category3/sub1/'
done < <(
awk '
NR == FNR {
if ( match($0,/Fail at (.*) is not found/,a) ) {
ARGV[ARGC++] = a[1]
}
else {
print > "newlog.txt"
}
next
}
/^CARD=[0-9]/ {
print FILENAME
nextfile
}
' convert.20231010.log
)
Если у вас нет GNU awk, сделайте это вместо этого с любым awk, который будет работать немного медленнее, если ваш awk не поддерживает nextfile (немногие другие awk поддерживают третий аргумент для match(), но многие поддерживают nextfile и оператор nextfile подойдет). ничего, если не поддерживается, поэтому это безвредно):
#!/usr/bin/env bash
while IFS= read -r file; do
[[ -f "$file" ]] &&
>&2 echo mv -f -- "$file" '/home/category3/sub1/'
done < <(
awk '
BEGIN {
beg = "Fail at "
end = " is not found"
begLgth = length(beg)
allLgth = length(beg end)
}
NR == FNR {
if ( match($0,beg ".*" end) ) {
ARGV[ARGC++] = substr($0,RSTART+begLgth,RLENGTH-allLgth)
}
else {
print > "newlog.txt"
}
next
}
/^CARD=[0-9]/ {
print FILENAME
nextfile
}
' convert.20231010.log
)
[[ -f "$file" ]] && в цикле оболочки защищает нас от любых проблем, если одно и то же имя файла появляется во входных данных несколько раз или /^CARD=[0-9]/ совпадает несколько раз в одном файле, а ваш awk не поддерживает nextfile, и поэтому мы, возможно, уже переместили его на этом этапе. точка в цикле оболочки.
Оригинальный ответ:
$ cat tst.sh
#!/usr/bin/env bash
regexp='Fail at (.*) is not found'
while IFS= read -r line; do
file = ""
[[ $line =~ $regexp ]] && file = "${BASH_REMATCH[1]}"
if [[ -f "$file" ]] && ! grep -q '^CARD=[0-9]' "$file"; then
>&2 echo mv -f -- "$file" '/home/category3/sub1/'
else
printf '%s\n' "$line"
fi
done < convert.20231010.log > newlog.txt
Удалите >&2 echo, когда закончите тестирование и убедитесь, что скрипт сделает то, что вы хотите.
Другой (возможно, крайне неудобный) метод тестирования — добавить -i к вызову mv.
Привет @Эд Мортон, что это за фраза [[ $line =~ $regexp ]] && file = "${BASH_REMATCH[1]}"
проверяет, соответствует ли содержимое переменной line, например. 2024-05-17 00:14:02.447 Fail at /home/category1/sub1/ABCXYZ01 00054 is not found, сопоставьте содержимое переменных regexp, Fail at (.*) is not found и, если да, установите file в любую часть line, совпадающую с .* в скобках в regexp, т. е. /home/category1/sub1/ABCXYZ01. Это похоже на file=$(printf '%s\n' "$line" | sed -n 's/.*Fail at \(.*\) is not found.*/\1/p'), но со встроенными функциями bash вместо внешних команд и дополнительных процессов.
Ладно, я понял. Кстати, мой журнал очень огромный, в нем ~ 1 миллион строк. Пока не могу использовать while IFS= read -r line; do ....done, очень медленно, если размер файлов очень большой, а количество строк в файле очень велико. Каким-то образом можно сначала использовать grep ""Fail at (.*) is not found, это очень быстро, и можно найти 2 строки с правильным условием. После этого продолжайте обрабатывать только эти две строки. @ЭдМортон
В своем вопросе вы должны были сказать, что ваш входной файл огромен, и поэтому скорость выполнения имеет большое значение. Я добавил новый скрипт, который будет на несколько порядков быстрее исходного.
Пожалуйста, задавайте только один вопрос в каждом посте. Каждая ваша проблема индивидуально освещается существующими вопросами; пожалуйста, поищите, прежде чем спрашивать. Кроме того, в вашем сценарии есть ряд стилистических проблем; попробуйте shellcheck.net и посмотрите также Правильная заглавная буква переменных Bash и сценария оболочки