긴 명령 문자열을 작성하는 방법은 무엇입니까?

긴 명령 문자열을 작성하는 방법은 무엇입니까?

다음과 같이 많은 파이프에서 작동하는 일련의 명령이 있습니다.

awk '{ if ($8 ~ "isad") {print $2, $5, "SE"} else {print $2, $5, "ANT"} }' "/var/log/apache2/other_vhosts_access.log" | grep -v '127.0.0.1' | tr '[' '\0' | tr [:lower:] [:upper:] | sort -t' ' -s -k3

이는 기본적으로 Apache 로그를 필터링하고 세 개의 정보 열을 인쇄합니다. 첫 번째 열은 IP 주소, 두 번째 열은 시간, 세 번째 열은 문자열입니다. 출력은 모든 열을 기준으로 정렬될 수 있으므로 "-m"을 사용하여 시간 필드를 정렬해야 합니다. 정렬 순서를 반대로 할 수도 있습니다.

정렬할 매개변수를 저장하고 결합된 문자열이 실행되도록 하는 문자열을 원합니다. 이 같은:

$AWK_CMD | $SORT_CMD $SORT_KEY $SORT_REV

어디

SORT_CMD="sort -t' '"
SORT_KEY="-k$1"      # $1 from cmd line arg
SORT_REV="$2"        # Either -r or blank

이와 같은 문자열을 만들 수 있으면 괜찮아 보입니다. 문제는 실행 방법입니다. 다음과 같은 오류가 발생합니다.

awk '{ if ($8 ~ "isad") {print $2, $5, "SE"} else {print $2, $5, "ANT"} }' "/var/log/apache2/other_vhosts_access.log" | grep -v '127.0.0.1' | tr '[' '\0' | tr [:lower:] [:upper:] | sort -t' ' -s -k3
Running ...
awk: '{
awk: ^ invalid char ''' in expression

정렬이 올바르게 정렬되지 않으면 무시하십시오. 이 문제는 해결될 수 있습니다. 최종 명령 문자열을 단계별로 작성하는 방법을 알고 싶습니다. 스크립트에서 이 명령을 실행하는 방법은 다음과 같습니다.

$final_cmd
`$final_cmd`

편집: 내가 사용해 본 스크립트

KEY=$1      # Values {1, 2, 3}
REVERSE=$2  # Values {0, 1} 

SORT_CMD="sort -t' ' -s"
SORT_KEY="-k$KEY"
if [[ $KEY -eq 2 ]]
then
    SORT_KEY="-m -k2"
fi

if [[ $REVERSE -eq 1 ]]
then
    SORT_REV="-r"
else
    SORT_REV=
fi

final_cmd="awk '{ if (\$8 ~ \"isad\") {print \$2, \$5, \"SE\"} else {print \$2, \$5, \"ANT\"} }' $LOG_FILE '|' grep -v '127.0.0.1' '|' tr '[' '\0' '|' tr [:lower:] [:upper:] '|' $SORT_CMD $SORT_KEY $SORT_REV"

echo $final_cmd
echo "Running ..."
$final_cmd

답변1

다양한 부분을 셸 함수에 넣을 수 있습니다.

awkfilter() {
    awk '{ if ($8 ~ "isad") {print $2, $5, "SE"} else {print $2, $5, "ANT"} }'
}

toupper() {
    tr '[:lower:]' '[:upper:]'
}

dosort() {
    sort -t' ' -s -k3
}

awkfilter < /var/log/apache2/other_vhosts_access.log |
  grep -vF 127.0.0.1 |
  tr '[' '\0' |
  toupper |
  dosort

그러면 선택 사항을 더 쉽게 만들 수 있습니다.

dosort() {
    rev=
    if [ "$2" = "reverse" ]
    then
        rev=-r
    fi
    sort -t' ' -s -k"$1" ${rev+"$rev"}
}

명령줄이 너무 길어지기 시작하면 스크립트로 작성하고 함수를 사용하여 여러 부분으로 나누는 것이 매우 도움이 되는 경우가 많습니다.

답변2

awk '{ ... }'쉘 프롬프트나 쉘 스크립트에서 실행할 때 쉘은 따옴표를 구문 분석하고 awk따옴표 없이 인수를 전달합니다. 무슨 일이 일어나든 매개 변수에 따옴표를 사용하여 실행하면 됩니다.

편집: 질문을 업데이트하면서 필요한 것은 입니다 sh -c "$final_cmd".

답변3

모든 경우에 변수에 옵션이 저장된 명령을 실행하려면 배열을 지원하는 셸을 사용하세요.

bash예를 들어, 예제 코드는 다음과 같이 변환됩니다(변수 확장 등은 큰따옴표로 묶어야 함).

#!/bin/bash

key=$1      # Values {1, 2, 3}
reverse=$2  # Values {0, 1} 

sort_key=()
if [ "$key" -eq 2 ]; then
    sort_key=( -m  )
fi

if [ "$reverse" -eq 1 ]; then
    key+='r'
fi

sort_key+=( -k "$key" )

set -x

awk '$8 ~ "isad" { print $2, $5, ($8 ~ "isad" ? "SE" : "ANT") }' "$log_file" |
grep -Fv '127.0.0.1'          |
tr '[:lower:][' '[:upper:]\0' |
sort -t ' ' -s "${sort_key[@]}" 

이 특별한 경우에는 더 의미가 있을 수 있습니다.기능 사용그러나 배열은 예를 들어 스크립트의 자체 명령줄 인수를 수정하여 생성된 경로 이름이나 명령줄 인수의 수를 알 수 없는 경우에 유용합니다.

관련된:

관련 정보