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

wan*_*rry 2 bash find centos

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

\n
[root@TENCENT64 /tmp/test]# cat test_ccd.log \nccd0.log:01-28 09:33:18:461 1254 F NORMAL\nccd0.log:01-28 09:33:18:461 1254 F FATAL \nccd0.log:01-28 09:34:30:827 1254 E ALARM\n[root@TENCENT64 /tmp/test]# cat test_mcd.log \nmcd0.log:01-29 09:33:18:461 1254 F NORMAL\nmcd0.log:01-29 09:33:18:461 1254 F FATAL \nmcd0.log:01-29 09:34:30:827 1254 E ALARM\n
Run Code Online (Sandbox Code Playgroud)\n

我想生成以下备份文件

\n
[root@TENCENT64 /tmp/test]# cat test_ccd.log.txt\nccd0.log:01-28 09:33:18:461 1254 F FATAL \nccd0.log:01-28 09:34:30:827 1254 E ALARM\n[root@TENCENT64 /tmp/test]# cat test_mcd.log.txt\nmcd0.log:01-29 09:33:18:461 1254 F FATAL \nmcd0.log:01-29 09:34:30:827 1254 E ALARM\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
[root@TENCENT64 /tmp/test]# cat /etc/redhat-release \nCentOS Linux release 7.2 (Final)\n\n# this commands hangs for ever\n[root@TENCENT64 /tmp/test]# find . -name "*.log" -type f -exec sh -c 'grep -E "ALARM|FATA:" 1>>"$0.txt"' {} \\;\n\n# this commands reports the error and the output was missed up\n[root@TENCENT64 /tmp/test]# find . -name "*.log" -type f -exec sh -c 'grep -R -E "ALARM|FATA:" 1>>"$0.txt"' {} \\;\ngrep: input file \xe2\x80\x98test_mcd.log.txt\xe2\x80\x99 is also the output\ngrep: input file \xe2\x80\x98test_ccd.log.txt\xe2\x80\x99 is also the output\n\n# the output for each file is not correct\n[root@TENCENT64 /tmp/test]# cat test_mcd.log.txt\ntest_mcd.log:mcd0.log:01-29 09:34:30:827 1254 E ALARM\ntest_ccd.log:ccd0.log:01-28 09:34:30:827 1254 E ALARM\n[root@TENCENT64 /tmp/test]# cat test_ccd.log.txt\ntest_mcd.log:mcd0.log:01-29 09:34:30:827 1254 E ALARM\ntest_ccd.log:ccd0.log:01-28 09:34:30:827 1254 E ALARM\ntest_mcd.log.txt:test_mcd.log:mcd0.log:01-29 09:34:30:827 1254 E ALARM\ntest_mcd.log.txt:test_ccd.log:ccd0.log:01-28 09:34:30:827 1254 E ALARM\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
# create the backed folder on the NFS share, like /data/backup/1.1.1.1/alarm_history\nip=`hostname -I|awk '{print $1}'` && mkdir -p /data/backup/${ip}/alarm_history\n\n# 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\nip=`hostname -I|awk '{print $1}'` && find /data/backup/${ip} -name '*.log' -type f -exec sh -c '\n    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"\n' 'find-sh' {} \\;\n
Run Code Online (Sandbox Code Playgroud)\n

它会产生两个错误:

\n
find-sh: line 1: /data/backup//alarm_history//data/backup/11.62.17.249/manager/manager_mcd0.log.alarm: No such file or directory\nfind-sh: line 1: /data/backup//alarm_history//data/backup/11.62.17.249/manager/manager_mcd0_stat.log.alarm: No such file or directory\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

Fre*_*ddy 6

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

grep -E "ALARM|FATA:" 1>> "$0.txt"
Run Code Online (Sandbox Code Playgroud)

应该

grep -E "ALARM|FATAL" "$0" > "$0.txt"
Run Code Online (Sandbox Code Playgroud)

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


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

find . -name '*.log' -type f -exec sh -c '
    grep -E "ALARM|FATAL" "$1" > "$1.txt"
' 'find-sh' {} \;
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:

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

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" {} +
Run Code Online (Sandbox Code Playgroud)