불필요하게 여러 개의 중복 행 -sed
postgresql 데이터베이스에서 주소를 선택한 다음 SSH를 통해 선택한 주소에 연결하고 각 호스트 구성의 올바른 위치에 특정 줄을 추가하는 작업이 있습니다.
예를 들어, 중간에 값이 포함된 파일이 있는데, 다른 값을 가진 새 행을 삽입해야 합니다.
# grep hostname config.cfg
hostname, port = 2234: Vasya
hostname, ip address: John, 192.168.1.5
hostname: Andrew
예를 들어 다음 줄 다음
hostname: Andrew
새 행에 새 값을 삽입해야 합니다.
hostname: Sheglina
나는 이렇게 합니다(먼저 하나의 호스트를 시도합니다):
for HOST in 192.168.1.1; do ssh $HOST "for VALUE in $(nl -ba /root/config.cfg|grep hostname | tail -1 | awk '{print $1}'); do sed -i $VALUE'a\hostname: Sheglina'/root/config.cfg; done"; done
이 명령은 가상 머신용입니다.
# grep hostname config.cfg
hostname, port = 2234: Vasya
hostname, ip address: John, 192.168.1.5
hostname: Andrew
hostname: Sheglina
하지만 실제 서버에서 필터를 통해 IP 주소를 선택한 후 다음 명령을 적용하려고 합니다.
for HOST in $(psql -U postgres name_db -c "SELECT name, ip_address FROM servers ORDER BY ip_address;" | grep -i 'moscow' | awk '{print $5}'); do ssh $HOST "for VALUE in $(nl -ba /root/config.cfg|grep hostname | tail -1 | awk '{print $1}'); do sed -i $VALUE'a\hostname: Sheglina '/root/config.cfg;done"; done
그런 다음 각 줄에서 호스트 이름:Sheglina 줄이 반복됩니다./루트/config.cfg, 한곳에 있지 않습니다. 필요하지 않습니다. 이 명령이 가상 머신에서는 작동하지만 서버에서는 작동하지 않는 이유를 이해할 수 없습니다. 클러스터 내 별도의 노드로 가서 같은 노드에 대해 명령을 실행해도 여전히 중복된 라인이 나오는데... 이유가 무엇일까요?
실제 서버에서는 다음과 같습니다.
# grep hostname config.cfg
hostname: Sheglina
hostname: Sheglina
hostname: Sheglina
hostname: Sheglina
...
호스트 이름 값이 있는 이전 행은 파일에 남아 있지만 어떤 이유로 Sheglina 행이 모든 행에서 반복됩니다.
답변1
당신은 필요한 것보다 일을 더 복잡하게 만들고 있습니다. 길고 복잡하며 읽기 어려운 한 줄로 모든 작업을 수행하는 대신 단계별로 나누어 순차적으로 수행하세요.
이 스크립트는 두 가지 작업을 수행해야 합니다.
- 이름 필드가 psql과 유사한 IP 주소 목록 가져오기
moscow
(대소문자 구분 사용) - 포함된 라인 바로 뒤에 를 사용하여 각 라인을 연결
ssh
하고 삽입합니다 .hostname: Sheglina
/root/config.cfg
hostname: andrew
예를 들어:
#!/bin/bash
city='moscow'
sql="SELECT DISTINCT ip_address FROM servers WHERE name ILIKE '$city'"
# get the query output into an array called 'hosts'
hosts=( $(psql -U postgres name_db -t --csv -c "$sql") )
for host in "${hosts[@]}"; do
ssh "$host" "sed -i -e 's/^hostname: andrew/&\nhostname: Sheglina/i' /root/config.cfg"
done
이는 psql의 내장 옵션을 사용하여 필요한 데이터를 올바른 형식으로 추출합니다. -t
머리글 및 바닥글 출력을 억제하고 --csv
쉼표로 구분된 형식을 요청합니다. SQL 쿼리는 일치하는 값만 선택합니다. 이를 grep 또는 awk로 파이프할 필요가 없으며 쿼리에 "DISTINCT"를 사용하여 중복을 방지합니다.
다음으로 ssh
각 호스트에 연결하는 데 사용되며 sed는 그 뒤에 검색 hostname: andrew
하고 추가하는 데 사용됩니다.hostname: Sheglina
참고: 셸에서 올바른 인용은 어려울 수 있습니다. 특히 인용이 필요한 다른 프로그램(예: psql 또는 ssh)에 인용 값을 전달해야 하는 경우 더욱 그렇습니다. printf '%q'
문자열을 해당 명령과 함께 사용할 수 있는 적절하게 인용된 형식으로 변환하는 형식을 사용할 수 있지만 , 인용 앞에 posix와 유사한 스타일을 사용하도록 지시하지 않는 한 postgres는 자체 인용/이스케이프 스타일을 사용합니다 E
. 이는 인용된 문자열에 posix 스타일 문자열 이스케이프가 포함될 수 있음을 postgres에 알려줍니다.
즉 , E'quoted-string'
단지 'quoted-string'
.
예를 들어, $city에 셸과 postgres에서 이스케이프해야 하는 문자가 포함되어 있는 경우 다음과 같이 사용하세요.
sql="SELECT DISTINCT ip_address FROM servers WHERE name ILIKE E'%"$(printf "%q" "$city")"'"