Bash 스크립트는 Firewalld에서 서비스 목록을 삭제할 수 없습니다.

Bash 스크립트는 Firewalld에서 서비스 목록을 삭제할 수 없습니다.

firewalldBash 스크립트를 통해 구성된 모든 기존 서비스를 지우려고 합니다 .

# produces {cockpit,dhcpv6-client,ssh} as an example
local EXISTING_SERVICES="{$(firewall-cmd --permanent --list-service | sed -e 's/ /,/g')}"
# firewall-cmd --permanent --remove-service={cockpit,dhcpv6-client,ssh}
firewall-cmd --permanent --remove-service="${EXISTING_SERVICES}"

실행 시 firewall-cmd다음을 반환합니다.

Warning: NOT_ENABLED: {cockpit,dhcpv6-client,ssh}
success

firewall-cmd문제는 비활성화할 서비스 목록이 목록이 아닌 단일 서비스 이름으로 해석된다는 점인 것 같습니다 . 쉘에서 수동으로 실행하면 정확히 동일한(복사/붙여넣기) 명령이 예상대로 작동합니다.

복사할 스크립트 예:

EXISTING_SERVICES="{$(firewall-cmd --permanent --list-service | sed -e 's/ /,/g')}"
echo "firewall-cmd --permanent --remove-service=${EXISTING_SERVICES}"
firewall-cmd --permanent --remove-service="${EXISTING_SERVICES}"

결과:

쉘 결과

스크립트를 통해 실행하는 것과 직접 쉘 명령을 통해 실행하는 것의 차이점은 무엇입니까?


업데이트: @fra-san이 제안한 대로 스크립트 실행을 시도했는데 set -x스크립트에서 실행하면 다음과 같은 결과가 나타납니다.

결과

쉘에서 실행했을 때의 결과는 다음과 같습니다.

여기에 이미지 설명을 입력하세요.

대화형으로 실행하면 셸(및/또는 방화벽)이 다르게 동작하는 것처럼 보이고 서비스 목록을 3개의 별도 --remove-service=플래그로 확장합니다. 이는 매우 예상치 못한 동작입니다.

답변1

firewall-cmd이와 관련하여 스크립트에서 명령을 실행하는 것과 대화식으로 실행하는 것 사이에는 차이가 없습니다. 대신 근본적으로 다른 두 가지 명령을 실행하고 있습니다.

당신이 행동에서 보는 것은버팀대 확장: 주문하다

firewall-cmd --permanent --remove-service={cockpit,dhcpv6-client,ssh}

Bash에 의해 확장됨

firewall-cmd --permanent --remove-service=cockpit --remove-service=dhcpv6-client --remove-service=ssh

이는 스크립트와 명령줄 모두에서 발생합니다. 그러나 쉘은 추가 확장 트리거 문자를 검색하기 위해 확장 결과를 구문 분석하지 않습니다. 따라서 명령은

firewall-cmd --permanent --remove-service="${EXISTING_SERVICES}"

스크립트에서 다음으로 확장합니다.

firewall-cmd --permanent --remove-service={cockpit,dhcpv6-client,ssh}

그리고 해당 형식으로 작동합니다(중괄호 안의 표현식은 이 시점에서 문자 그대로 받아들여집니다).

이것은 유효한 명령이 아닌 것 같습니다 firewall-cmd. 인용하다man firewall-cmd, 구문 은 다음 --remove-service과 같습니다

... --remove-service=service

서비스를 삭제합니다. 이 옵션은 여러 번 지정할 수 있습니다.

한 번에 여러 서비스를 제거하는 데 권장되는 예상 방법은 다음과 같습니다.

firewall-cmd ... --remove-service=foo --remove-service=bar ...

Bash를 사용하면 배열을 사용하여 활성화된 서비스를 저장하고 이를 제거하기 위한 해당 옵션 목록을 작성할 수 있습니다.

services=( $(firewall-cmd --permanent --list-services) )
firewall-cmd --permanent "${services[@]/#/--remove-service=}"

${services[@]/#/--remove-service=}Bash 매개변수 확장의 패턴 교체 형식은 어디에 있습니까? #각 배열 요소의 시작 부분에 있는 빈 문자열을 일치시키고 로 바꿉니다 --remove-service=.

비록 덜 효율적이지만 어떤 경우에는 if firewall-cmd의 종료 상태가 변경되므로 한 번에 하나의 서비스를 추가/제거하는 것이 더 실용적일 수 있습니다.0적어도아무리 많은 작업이 실패하더라도 하나의 작업은 성공합니다. 그렇다면 다음을 선호할 수 있습니다.

services=( $(firewall-cmd --permanent --list-services) )
for serv in "${services[@]}"
do
  firewall-cmd --permanent --remove-service="$serv" || echo "failed: $serv" >&2
done

관련 정보