Bash - SSH를 통해 원격 호스트에 배열 전달

Bash - SSH를 통해 원격 호스트에 배열 전달

smartctl여러 원격 호스트에 로그인하고 (패키지의) 배열에 정의된 디스크에서 실행되는 Bash 스크립트를 작성했습니다 . 배열을 원격 호스트에 전달할 수 있지만 스크립트는 첫 번째 요소를 계속해서 반복해서 표시합니다. 배열을 문자열로 처리하고 첫 번째 요소 이후의 모든 요소를 ​​무시하는 것처럼 보입니다.smartmontoolsDISKS

DISKS=("/dev/sda" "/dev/sdb" "/dev/sdc")
HOSTS=("Ariadne" "Nyx")

for i in "${HOSTS[@]}"; do
    ssh "$i" "bash" << EOF
        for j in "${DISKS[@]}"; do
            echo "$j"
        done
EOF
done

원격 호스트에서 (두 번째 for 루프 이전에) 배열을 정의하려고 시도했지만 DISKS=("${DISKS[@]}")도움이 되지 않았습니다.

SSH를 통해 배열을 원격 호스트에 올바르게 전달한 다음 배열을 반복하려면 어떻게 해야 합니까?

답변1

다음과 같이 배열의 정의를 원격으로 전달할 수 있습니다 bash(이는 원격 사용자의 로그인 셸이 이라고 가정합니다 bash).

DISKS_definition=$(typeset -p DISKS)
for i in "${HOSTS[@]}"; do
  ssh "$i" "$DISKS_definition"'
    for j in "${DISKS[@]}"; do
      echo "$j"
    done'
done

또는 여기에 설명된 방법을 사용하는 경우:

DISKS_definition=$(typeset -p DISKS)
for i in "${HOSTS[@]}"; do
  ssh "$i" bash <<EOF
    $DISKS_definition
    for j in "\${DISKS[@]}"; do
      echo "\$j"
    done
EOF
done

ssh클라이언트와 서버가 변수 전달을 허용하는 경우 LC_*이 작업도 수행할 수 있습니다.

DISKS_definition=$(typeset -p DISKS)
for i in "${HOSTS[@]}"; do
  LC_DISKS=$DISKS_definition ssh "$i" bash <<'EOF'
    eval "$LC_DISKS"
    for j in "${DISKS[@]}"; do
      echo "$j"
    done
EOF
done

참조의 모든 내용은 확장을 실행하는 로컬 또는 원격 셸을 결정합니다. 변수는 큰따옴표 내에서 확장되고 여기에서는 구분 기호가 인용되지 않은 문서 <<'EOF'에서 확장된다는<<EOF 점을 기억하세요. 로컬 쉘에 의해 확장됨).

비ASCII 데이터가 포함된 배열의 경우 로컬 및 원격 시스템의 로캘에 대한 문자 집합이 동일한지 확인하거나 최소한 UTF-8 이외의 멀티바이트 문자 집합을 사용하지 않아야 합니다.

bash-4.3$ locale charmap
ISO-8859-1
bash-4.3$ a=($'foo\xa3$(uname>&2)bar' baz)
bash-4.3$ a_definition=$(typeset -p a)
bash-4.3$ LC_ALL=zh_HK.big5hkscs bash -c "$a_definition"
Linux

다른 문자 세트로 전환하면 내용의 $a_definition의미가 달라집니다(여기서 uname>&2명령이 실행됩니다).

답변2

귀하는 echo "$j"명령줄이 평가될 때 평가되므로 for 루프 내에서는 실제로 변수가 아닌 상수(및 정의되지 않음)입니다.sshfor j...

이 시도

for i in "${HOSTS[@]}"; do
    ssh "$i" "bash" << EOF
        for j in "${DISKS[@]}"; do
            echo "\$j"
        done
EOF
done

또는 $DISKS배열에 공백 없이 안전한 단어가 포함되어 있는 경우.

for i in "${HOSTS[@]}"; do
    ssh "$i" "for j in ${DISKS[@]}; do echo \"\$j\"; done"
done

이와 같은 문제를 해결하기 위해 제가 선호하는 방법은 필요한 작업을 수행하는 스크립트를 만들어 각 원격 서버에 상주시키는 것입니다. 그런 다음 각 서버에서 스크립트를 호출하는 과정은 간단하고 간단합니다.

for h in "${HOSTS[@]}"; do ssh "$h" /usr/local/bin/myscript; done

스크립트가 오래될까봐 걱정된다면 실행하기 전에 로컬 시스템에서 파일을 복사하는 것이 불가능한 작업은 아닙니다. 다음과 같이 작동할 수 있습니다.

for h in "${HOSTS[@]}"
do
    scp -p /local/path/to/myscript "$h":myscript.$$
    ssh "$h" "myscript.$$; rm -f myscript.$$"
done

관련 정보