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매개변수가 누락되었으며 예상 결과를 얻으려면 매개 :변수가 있어야 합니다 .L

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

~해야 한다

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

(또는 결과를 기존 파일에 추가하려면 >>또는 사용)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

관련 정보