bash for 루프의 마지막 반복 결정

bash for 루프의 마지막 반복 결정

구성 파일에 몇 줄을 추가하는 루프가 있습니다.

for i in ${H//,/ }
do
        sed -i "7i\                      host($i) or" $configPath/$g.conf
done

$H는 쉼표로 구분된 변수입니다(예: host1,host2,host4,host10).

다음을 반환합니다.

                  host(host10) or
                  host(host4) or
                  host(host2) or
                  host(host1) or

하지만 내가 달성하고 싶은 것은 다음과 같습니다.

                  host(host10) or
                  host(host4) or
                  host(host2) or
                  host(host1)

혹은 그 반대로도:

                  host(host1) or
                  host(host2) or
                  host(host4) or
                  host(host10)

내가 이 작업을 수행하는 방법에 대한 올바른 방향을 찾는 데 도움을 줄 수 있는 사람이 있습니까?

답변1

이 문제는 대부분의 프로그래밍 언어에서 동일한 형태로 발생합니다. 어떻게든 접미사를 건너뛰는 것은 복잡할 것입니다. 나는 쉘 구문에 대해 논의하지 않을 것이며, 사람들이 일반적으로 이 문제에 접근하는 방법에 대한 의사코드 개요만 설명하겠습니다.

# get it over with at the beginning:
print a[0] (no newline)
loop from a[1] onwards:
   print "or\n"
   print a[i]
print "\n" #terminate the last one

이 경우에는 인덱스 테스트가 포함되지 않기 때문에(언어가 bash 및 Python과 같이 배열의 직접 반복을 지원하는 경우) 인덱스를 반복하거나 모든 요소를 ​​반복하여(첫 번째 요소를 건너뛰는 방식으로) 작동할 수 있습니다.

0에서 시작하여 마지막 항목을 건너뛰고 루프 외부에서 처리할 수도 있지만(위 미러 참조), 마지막 항목을 건너뛰는 것은 일반적으로 더럽고 불가능할 수도 있습니다(마지막 항목을 건너뛰려면 마지막 항목임을 알아야 하지만, 첫 번째 항목은 언제든지 즉시 건너뛸 수 있습니다. 예를 들어,스트림에서 요소를 읽고 어느 것이 마지막 요소인지 미리 알 수 없는 경우 이 형식이 유일한 옵션입니다.!

또 다른 방법:

# test a loop counter
N = length of array
loop with indices:
   if i==N-1:
      print a[i]
   else:
      print a[i],"or"

이 경우 요소 수를 알아야 하며 인덱스를 지속적으로 테스트합니다. 따라서 인덱스를 반복하거나 인덱스를 개별적으로 추적해야 합니다(루프 앞에 i=0을 설정하고 루프 안에 i++를 설정).

나는 이것을 레시피로 작성하고 있으며 bash 구현은 여러분에게 맡기겠습니다.

답변2

제가 보기에는 코드를 약간만 변경하면 됩니다. 첫 번째 루프에서 비어 있는 변수에 "or"를 넣으면 됩니다.

operator=''
for i in ${H//,/ }
do
        sed -i "7i\                      host($i)$operator" "$configPath/$g.conf"
        operator=' or'
done

답변3

일반적으로 텍스트 처리에 쉘 루프를 사용하고 싶지 않습니다. 여기서는 다음을 사용합니다 awk.

export H
awk 'NR == 7 {
  s = ENVIRON["H"]
  gsub(/,/, ") or\n   host(", s)
  print "   host(" s ")"}
  {print}' file

GNU에 내부 편집 옵션이 sed있는 것처럼 GNU (4.1.0부터)에도 동등한 옵션으로 1이 있습니다.-iawk-i /usr/share/awk/inplace.awk

텍스트 파일을 편집하려면 텍스트 편집기를 사용해야 한다고 생각할 수도 있습니다. 사용 vim:

export H
vim -esc '
  let @a=$H
  6put a
  s/.*/host(&)/
  s/,/) or\rhost(/g
  x' file

^사용하지 마세요-i inplace현재 작업 디렉터리(as or)에서 확장 기능을 먼저 gawk로드 하려고 하면 누군가가 해당 디렉터리에 악성 코드를 심었을 수 있습니다. 시스템과 함께 제공되는 확장 프로그램 의 경로 는 다를 수 있습니다. 출력을 참조하세요.inplaceinplaceinplace.awkinplacegawkgawk 'BEGIN{print ENVIRON["AWKPATH"]}'

답변4

원래 질문에서 "sed"를 사용하는 대신 아이디어를 설명하기 위해 echo를 사용하여 더 간단한 질문을 작성했습니다. 공백으로 구분된 항목을 반복하는 대신:

  • 먼저 반복 횟수를 결정하기 위해 "," 교체 뒤의 단어 수를 얻습니다.
  • "()"를 사용하여 빈 문자열을 배열로 변환
  • 반복 횟수
  • "또는" 부분을 조건의 출력으로 가져와 변수에 넣습니다.
  • 반복을 통해 배열 부분 집합
  • echo/sed 등도 있습니다.

    #!/bin/bash
    
    H="host1,host2,host3"
    H2=${H//,/ }
    N=`echo $H2 | wc -w`
    H3=($H2)
    
    for ((i = 1; i <= $N; i++))
    do
        if [ "$i" -eq "$N" ]; then OR=""; else OR=" or"; fi
        ITEM=${H3[$i-1]}
        echo "$ITEM$OR"
    done
    

관련 정보