smartctl
여러 원격 호스트에 로그인하고 (패키지의) 배열에 정의된 디스크에서 실행되는 Bash 스크립트를 작성했습니다 . 배열을 원격 호스트에 전달할 수 있지만 스크립트는 첫 번째 요소를 계속해서 반복해서 표시합니다. 배열을 문자열로 처리하고 첫 번째 요소 이후의 모든 요소를 무시하는 것처럼 보입니다.smartmontools
DISKS
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 루프 내에서는 실제로 변수가 아닌 상수(및 정의되지 않음)입니다.ssh
for 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