빈 배열 요소를 0으로 설정하는 방법은 무엇입니까?

빈 배열 요소를 0으로 설정하는 방법은 무엇입니까?

명령 결과를 출력 배열로 보내는 스크립트를 작성 중입니다. 여기에는 서버의 로그를 확인하고 해당 크기를 검색하는 작업이 포함되지만 경우에 따라 서버에 장애 조치 호스트가 있습니다. 이러한 경우 두 호스트를 모두 확인하고 값을 반환하는 스크립트가 필요합니다. 내가 겪고 있는 문제는 출력 배열 요소 중 하나라도 비어 있으면(검사 중인 파일이 서버에 존재하지 않고 해당 에코 디스플레이에 공백만 반환됨을 의미함) 이로 인해 배열 인덱스가 변경된다는 것입니다. 이는 보조 호스트 어레이 세트에 있어야 하는 항목이 기본 호스트 어레이 세트에 부딪히게 된다는 것을 의미합니다. 대신, 이동이 발생하지 않도록 이러한 빈 인덱스를 자리 표시자로 0으로 저장하고 싶습니다. 인덱스 오프셋이 분명해지는 곳은 다음과 같습니다.

echo The primary overall log value is ${output[0]}.
echo The primary obs log value is ${output[2]}.    
echo The primary tracks log value is ${output[4]}.  
echo
echo The secondary overall log value is ${output[6]}.
echo The secondary overall log value is ${output[8]}.
echo The secondary overall log value is ${output[10]}.

예를 들어 출력 [2]와 [4]가 비어 있으면 출력 [6]은 출력 [2]에 해당하는 행으로 위로 이동합니다. 이 솔루션을 시도했지만 운이 없습니다.

  s=0

  for x in "${output[@]}"
     do(
     x=
        if [[ -z $x ]];
        then(
        x=0
        echo $x)
        else echo
        fi
     s=s+1)
 done

이 모든 작업은 출력 에코가 발생하기 전에 0을 뱉어내고 인덱스 이동을 조정하지 않습니다.

참고: 출력 배열의 소스는 다음과 같습니다. 이를 수정하려는 시도는 다음과 같습니다.

for h in "${host[@]}"
do
    for path in "${paths[@]}"
    do
            output+=( $(ssh $h du -sh $path) )
            for x in "${!output[@]}";
            do(
                    if [[ -z "${output[$x]}" ]];
                    then output[$x]=0;
                    fi;
            )
            done

    done
done

호스트와 경로는 이미 정의된 배열입니다. 또한 액세스 가능한 호스트가 하나만 있으면 스크립트가 제대로 실행되고 배열 인덱싱에는 문제가 없다는 점도 확인했습니다.

답변1

예를 들어 출력 [2]와 [4]가 비어 있으면 출력 [6]은 출력 [2]에 해당하는 행으로 위로 이동합니다.

이 경우 실제로 2와 4를 null 값으로 바꾸는 것이 아니라 예상보다 적은 값을 가지게 됩니다.

배열 할당을 고려하십시오.

array1=(a b c d)
array2=(A D)

첫 번째는 , ~ 등 array1[0]으로 설정됩니다. 두 번째는 및 로 설정 됩니다 . 와 사이에 null 값이 있어야 하는지 알 수 있는 방법이 없습니다 . 과제에 명시적으로 나타나야 합니다.aarray1[1]barray2[0]Aarray2[1]DAD

array2=(A "" "" D)

다른 방법으로 배열을 채울 수도 있지만 output그 방법을 보여주지 않았기 때문에 이에 대해 언급할 수 없습니다. 위와 비슷한 상황이 발생할 수 있습니다. "빈" 값은 배열을 채우는 어떤 값에서도 전혀 값으로 간주되지 않습니다 output.

확장에서 배열에 할당하고 토큰화에 의존하는 경우 이를 피할 수 없습니다. (새 줄만 포함되어 있어도 IFS연속된 빈 줄 바꿈을 하나로 축소하여 빈 줄을 제거합니다.) 를 사용하는 경우 mapfile기본적으로 빈 줄이 배열 요소로 표시되어야 합니다.


어떤 경우든 빈 배열 요소를 0으로 만드는 루프는 루프 내부의 배열에 전혀 할당하지 않기 때문에 작동하지 않으며, 그렇게 했더라도 루프 본문은 하위 쉘(예: 괄호)에서 실행됩니다. (...)), 따라서 모든 할당은 루프 본문 외부에서 발생하지 않습니다.

for x in "${output[@]}"실제로 배열 요소를 효과적으로 수정하는 데 a를 사용할 수는 없습니다 . x배열 값의 복사본만 가져오고 이를 수정해도 원래 값은 변경되지 않기 때문입니다. 배열을 가리키도록 배열 인덱스를 반복해야 합니다.

somearray=(1 "" "" 4)
for i in "${!somearray[@]}"; do
    if [[ -z "${somearray[$i]}" ]]; then
        somearray[$i]=0;
    fi;
done
echo "${somearray[@]}"

인쇄 1 0 0 4.


추가한 예제 코드에서 할당은 output+=( $(ssh $h du -sh $path) )빈 요소를 추가하지 않습니다. 누락된 경로는 배열에서 생략됩니다. 먼저 생각해 보세요. du $path 경로가 존재하지 않으면 아무 것도 인쇄되지 않습니다. (stderr로 전송되고 명령 대체에 의해 포착되지 않는 오류는 제외.) 또한 빈 줄(또는 공백/탭)을 인쇄하더라도 토큰화는 연속 공백을 제거합니다.

예를 들어 array=( $( printf "foo\n\nbar\n" ) ), 두 개의 요소가 있는 배열을 생성합니다.

또한 루프에서 괄호를 바꾸면 하위 쉘이 시작되므로 배열에 대한 수정 사항은 해당 하위 쉘 내에서만 적용됩니다. 일반적으로 말하자면, 당신은아니요특별히 하위 쉘이 필요하다는 것을 알지 않는 한 괄호를 사용하여 쉘 명령을 그룹화할 수 있습니다.

"$(ssh ... du)"정확한 문자열을 얻기 위해 명령 대체( ) 주위에 따옴표를 넣을 수 있지만 경로 이름에서 크기를 분리할 수도 있습니다.

경로와 크기를 단일 배열로 수집하려면 다음과 같이 시도해 보세요.

for host in "${hosts[@]}"; do
    for path in "${paths[@]}"; do
        output="$(ssh "$host" du -sh "$path")"
        size="${output%%$'\t'*}"           # needs Bash/ksh/zsh
        size="${size:-0}"
        sizes+=( "$size" "$host:$path"  )
    done
done

이제 각 짝수 배열 요소에는 크기가 포함되고 각 홀수 배열 요소에는 분할 출력 du결과와 다소 유사한 해당 호스트 이름과 경로가 포함됩니다. 두 인수는 탭 문자 뒤의 모든 항목을 확장 output하고 제거한 다음 비어 있으면 크기를 0으로 바꿉니다.size

또는 다음을 빌드할 수 있습니다.연관 배열, 호스트 + 경로로 색인화됨:

declare -A array
...
    array["$host:$path"]=$size

관련 정보