원하지 않는 여러 중복 라인 - sed

원하지 않는 여러 중복 라인 - sed

불필요하게 여러 개의 중복 행 -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

당신은 필요한 것보다 일을 더 복잡하게 만들고 있습니다. 길고 복잡하며 읽기 어려운 한 줄로 모든 작업을 수행하는 대신 단계별로 나누어 순차적으로 수행하세요.

이 스크립트는 두 가지 작업을 수행해야 합니다.

  1. 이름 필드가 psql과 유사한 IP 주소 목록 가져오기 moscow(대소문자 구분 사용)
  2. 포함된 라인 바로 뒤에 를 사용하여 각 라인을 연결 ssh하고 삽입합니다 .hostname: Sheglina/root/config.cfghostname: 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")"'"

관련 정보