Bash 命令 find 与 exec 和 grep 无法正常工作,有什么问题吗?

Bash 命令 find 与 exec 和 grep 无法正常工作,有什么问题吗?

我想用关键字 ALARM/FATAL 过滤我的日志文件到另一个备份文件中,假设我有以下两个文件

[root@TENCENT64 /tmp/test]# cat test_ccd.log 
ccd0.log:01-28 09:33:18:461 1254 F NORMAL
ccd0.log:01-28 09:33:18:461 1254 F FATAL 
ccd0.log:01-28 09:34:30:827 1254 E ALARM
[root@TENCENT64 /tmp/test]# cat test_mcd.log 
mcd0.log:01-29 09:33:18:461 1254 F NORMAL
mcd0.log:01-29 09:33:18:461 1254 F FATAL 
mcd0.log:01-29 09:34:30:827 1254 E ALARM

我想生成以下备份文件

[root@TENCENT64 /tmp/test]# cat test_ccd.log.txt
ccd0.log:01-28 09:33:18:461 1254 F FATAL 
ccd0.log:01-28 09:34:30:827 1254 E ALARM
[root@TENCENT64 /tmp/test]# cat test_mcd.log.txt
mcd0.log:01-29 09:33:18:461 1254 F FATAL 
mcd0.log:01-29 09:34:30:827 1254 E ALARM

我尝试了以下命令来实现该目的,但它们都没有成功,请有人帮助纠正我做错的任何事情?

[root@TENCENT64 /tmp/test]# cat /etc/redhat-release 
CentOS Linux release 7.2 (Final)

# this commands hangs for ever
[root@TENCENT64 /tmp/test]# find . -name "*.log" -type f -exec sh -c 'grep -E "ALARM|FATA:" 1>>"$0.txt"' {} \;

# this commands reports the error and the output was missed up
[root@TENCENT64 /tmp/test]# find . -name "*.log" -type f -exec sh -c 'grep -R -E "ALARM|FATA:" 1>>"$0.txt"' {} \;
grep: input file ‘test_mcd.log.txt’ is also the output
grep: input file ‘test_ccd.log.txt’ is also the output

# the output for each file is not correct
[root@TENCENT64 /tmp/test]# cat test_mcd.log.txt
test_mcd.log:mcd0.log:01-29 09:34:30:827 1254 E ALARM
test_ccd.log:ccd0.log:01-28 09:34:30:827 1254 E ALARM
[root@TENCENT64 /tmp/test]# cat test_ccd.log.txt
test_mcd.log:mcd0.log:01-29 09:34:30:827 1254 E ALARM
test_ccd.log:ccd0.log:01-28 09:34:30:827 1254 E ALARM
test_mcd.log.txt:test_mcd.log:mcd0.log:01-29 09:34:30:827 1254 E ALARM
test_mcd.log.txt:test_ccd.log:ccd0.log:01-28 09:34:30:827 1254 E ALARM

当我尝试使用以下代码将备份警报保存到另一个位置时,事情也变得复杂,我有一个 NFS 共享来存储备份警报,并且每个警报都单独存储到共享上的文件夹(以 IP 地址命名)中,下面是我的命令

# create the backed folder on the NFS share, like /data/backup/1.1.1.1/alarm_history
ip=`hostname -I|awk '{print $1}'` && mkdir -p /data/backup/${ip}/alarm_history

# iterate through /data/backup/1.1.1.1 to find all the alarms and persist into /data/backup/1.1.1.1/alarm_history, /data/backup is a shared base and 1.1.1.1 is mounted on the current server
ip=`hostname -I|awk '{print $1}'` && find /data/backup/${ip} -name '*.log' -type f -exec sh -c '
    grep -E "ALARM|FATAL" "$1" >> "/data/backup/${ip}/alarm_history/$1.alarm" && sort -o "/data/backup/${ip}/alarm_history/$1.alarm" -u "/data/backup/${ip}/alarm_history/$1.alarm"
' 'find-sh' {} \;

它会产生两个错误:

find-sh: line 1: /data/backup//alarm_history//data/backup/11.62.17.249/manager/manager_mcd0.log.alarm: No such file or directory
find-sh: line 1: /data/backup//alarm_history//data/backup/11.62.17.249/manager/manager_mcd0_stat.log.alarm: No such file or directory

它们是两个问题,1,传递到命令“find”的 ${ip} 无法在 grep 中识别。 2. $1.alarm,$1是grep中的绝对路径,我怎样才能得到它的基本名称?

答案1

grep缺少参数,:应该是 anL以获得预期结果,因此

grep -E "ALARM|FATA:" 1>> "$0.txt"

应该

grep -E "ALARM|FATAL" "$0" > "$0.txt"

(或者如果您想将结果附加到现有文件,请使用>>or )1>>


由于$0命令名称和位置参数应该以 开头$1,因此您可以添加名称并将结果传递$1给脚本:

find . -name '*.log' -type f -exec sh -c '
    grep -E "ALARM|FATAL" "$1" > "$1.txt"
' 'find-sh' {} \;

sh或者使用尽可能少的调用来循环结果{} +

find . -name '*.log' -type f -exec sh -c '
    for file; do
        grep -E "ALARM|FATAL" "$file" > "${file}.txt"
    done
' 'find-sh' {} +

编辑:

我为目标目录添加了一个变量,该变量作为第一个参数传递给脚本。为了能够对生成的日志文件进行排序,我使用了一个临时文件。

ip=$(hostname -I | awk '{ print $1 }')
targetdir="/data/backup/$ip/alarm_history"
mkdir -p "$targetdir"

find "/data/backup/$ip" -name '*.log' -type f -exec sh -c '
    targetdir=$1; shift

    for file; do
            # extract the log filename from the path, append ".alarm", prepend directory
            targetfile=${targetdir}/${file##*/}.alarm

            grep -E "ALARM|FATAL" "$file" >> "$targetfile" \
                && mv "$targetfile" "${targetfile}.tmp" \
                && sort -o "$targetfile" -u "${targetfile}.tmp" \
                && rm "${targetfile}.tmp"
    done
' 'find-sh' "$targetdir" {} +

答案2

for作为循环这可能会更容易

例如

for file in *.log
do
  grep -E -- "ALARM|FATAL" "$file" > "$file.txt"
done

相关内容