여러 서버에 걸쳐 for 루프에서 sed 명령 사용

여러 서버에 걸쳐 for 루프에서 sed 명령 사용

여러 호스트에서 동일한 텍스트 파일을 조작하려고 합니다. 현재 가지고 있는 명령은 다음과 같습니다.

for host in $(cat /etc/hosts | grep text | cut -d' ' -f 1 | sort -u); do
    ssh $host \
    sudo sed -i "s/enabled = 1/enabled = 0/" /etc/yum.repos.d/testing.repo
done

sed 명령 자체는 아무런 문제 없이 호스트 시스템에서 로컬로 실행되지만 여기서 실행하면 다음과 같은 결과가 나타납니다.

sed: -e expression #1, char 9: unterminated `s' command

내가 뭘 잘못했나요?

답변1

이 시도,

for host in $(grep test /etc/hosts | cut -d' ' -f 1 | sort -u); do
    ssh $host 'sudo sed -i "s/enabled = 1/enabled = 0/" /etc/yum.repos.d/testing.repo'
done

원격 명령을 따옴표로 묶어야 합니다.

답변2

이렇게 바꿔보세요

for host in $(cat /etc/hosts | grep text | cut -d' ' -f 1 | sort -u); do
   ssh $host \
   "sudo sed -i \"s/enabled = 1/enabled = 0/\" /etc/yum.repos.d/testing.repo"
done

답변3

문제는 원격 호스트에서 실행될 명령이 적절하게 처리된 참조에 의존한다는 것입니다. 따옴표는 로컬 호스트가 아닌 원격 측에서 명령의 일부로 평가되어야 합니다. 이는 명령에 추가 따옴표가 필요함을 의미합니다.

현재 시도에서 명령을 올바르게 인용하지 않았기 때문에 원격 호스트의 공백으로 분할되었습니다. 그런 다음 sed명령은 로컬로 실행하는 것과 같습니다.

sed -i s/enabled = 1/enabled = 0/ /etc/yum.repos.d/testing.repo

오류 메시지에 나와 있듯이 s올바르게 종료되지 않은 명령이 포함되어 있습니다.

또한 명령 대체를 통한 반복은 우아하지 않고 위험합니다. 확장을 대체하는 값은 공백의 단어로 분할된 다음 파일 이름 생성(globbing)에 사용됩니다. 또한 루프가 첫 번째 반복을 시작하기 전에 명령 대체를 완전히 풀어야 합니다.

대신 read루프를 사용하세요.

awk '/text/ && !seen[$1]++ { print $1 }' |
while IFS= read -r remote; do
    ssh -n "$remote" \
        'sudo sed -i "s/enabled = 1/enabled = 0/" /etc/yum.repos.d/testing.repo'
done

여기에 주목하세요 ssh -n. ssh호스트의 표준 입력 스트림 읽기를 중지합니다 . 그렇지 않으면 awk명령의 출력을 읽게 됩니다. 또한 모든 변수 확장은 큰따옴표로 묶어야 합니다(필요하지 않은 경우를 제외하고).

이 문제를 해결하는 또 다른 방법은 각 원격 호스트에서 기존 파일을 편집하는 대신 파일을 푸시하는 것입니다.새로운파일을 각 컴퓨터에 복사합니다( scp또는 사용 가능 rsync). 그러나 이를 위해서는 파일이 모든 호스트에서 동일하게 보여야 합니다.

관련 정보