Bash의 배열에 몇 가지 문제가 있습니다.
A=( "127.0.0.1" "localhost" "aaa nnn cvcc" )
B=( "8.8.8.8" "dns" "bbb tttt rrrr")
for n in ${A} ${B} ; do
if ping -c3 ${n[0]};then
echo "${n[1]}"
for share in ${n[2]};do
echo $share
done
fi
done
배열의 두 번째와 세 번째 요소를 인쇄하고 싶지만 for 루프가 ping에서 중지됩니다. 그래서 작동합니다.
if ping -c3 ${A[0]};then
echo "${A[1]}"
for share in ${A[2]};do
echo $share
done
fi
정말 어리석은 짓이겠지만, 정말 미칠 것 같아요... 아이디어가 있으신가요? 미리 감사드립니다
답변1
A
루프는 실제로 and 의 첫 번째 요소인 and 를 반복합니다 B
. 이는 ${A[0]}
and 가 while 과 동일한 빈 문자열임을 ${B[0]}
의미합니다 .${n[1]}
${n[2]}
${n[0]}
$n
bash
버전 4.3 이상에서는 이름 참조 변수를 사용하여 이 작업을 수행할 수 있습니다.
#!/bin/bash
A=( 127.0.0.1 localhost alpha beta gamma theta )
B=( 8.8.8.8 dns itsy bitsy 'spider man' )
for variable in A B; do
declare -n array="$variable"
if ping -c3 "${array[0]}" >/dev/null; then
printf '%s\n' "${array[1]}"
printf '\t%s\n' "${array[@]:2}"
fi
done
변수를 반복하고 있습니다.이름 A
그리고 B
, 그 내용보다는. 루프 내에서 array
라는 변수에 대한 이름 참조를 만듭니다 $variable
. Now는 or array
로만 사용됩니다 .A
B
이 if
설명에서는 루프의 세 번째 배열 요소를 분할하기 위해 셸을 사용하지 않습니다. 대신, A
및 배열을 생성할 때 B
수동으로 분할 하고 printf
배열의 오프셋을 사용하여 단일 호출을 수행하여 요소를 출력합니다 array
. 읽기 쉽도록 각 요소 앞에 탭을 출력했습니다.
localhost
alpha
beta
gamma
theta
dns
itsy
bitsy
spider man
이 if
진술은 다음과 같이 쓸 수도 있습니다.
if ping -c3 "${array[0]}" >/dev/null; then
printf '%s: ' "${array[1]}"
( IFS=,; printf '%s\n' "${array[*]:2}" )
fi
나머지 배열 요소를 콜론 뒤에 쉼표로 구분된 목록으로 출력합니다.
localhost: alpha,beta,gamma,theta
dns: itsy,bitsy,spider man
참고: 위의 인용문은 우연이 아닙니다. 참조 배열을 확장하면 각 요소가 개별적으로 참조됩니다. 개별 요소를 인용하는 확장은 쉘이 공백으로 값을 분할하지 않도록 보장합니다(그리고 분할된 단어에 대해 파일 이름 글로빙을 수행하지 않음).
당신은 또한 볼 수 있습니다
/bin/sh
명명된 배열을 사용하지 않고도 이 작업을 수행 할 수도 있습니다 . 대신 위치 인수 목록을 사용하여 데이터를 보유하고 목록의 각 부분을 특수 단어( END
선택한 임의의 문자열인 를 사용합니다)로 끝냅니다. 그런 다음 목록을 반복하고 목록에서 요소를 제거합니다.
#!/bin/sh
set -- 127.0.0.1 localhost alpha beta gamma theta END \
8.8.8.8 dns itsy bitsy 'spider man' END
while [ "$#" -gt 0 ]; do
if ping -c 3 "$1" >/dev/null; then
printf '%s\n' "$2"
shift 2
while [ "$1" != END ]; do
printf '\t%s\n' "$1"
shift
done
else
while [ "$1" != END ]; do shift; done
fi
shift
done
답변2
이 답변은 귀하의 문제를 직접적으로 해결하지는 않지만 문제에 대한 대체 솔루션을 제공합니다. 배열에 의존하지 않습니다.
배열을 다루는 대신 파일을 사용하겠습니다. 제 생각에는 파일을 사용하면 프로그램에서 데이터를 분리할 수 있다는 장점이 있습니다. 작성 및 유지 관리가 더 쉽습니다.
이렇게 하려면 "공유"를 쉼표 ,
나 다른 문자로 구분하세요.
파일.txt
127.0.0.1 localhost aaa,nnn,cvcc
8.8.8.8 dns bbb,tttt,rrrr
failedip failed a,b,c
스크립트:
#!/bin/bash
# loop over the file's lines
while IFS=' ' read -r ip domain share; do
# a blank line to separate results at each loop
echo
# perform the `ping`, redirect to `/dev/null` if you don't need to print the output
if ping -c3 "$ip" &> /dev/null;then
echo "ping to $ip successful"
echo "domain: $domain"
# change the IFS to comma ',' in a subshell to parse the 'shares'
(IFS=,; printf "share: %s\n" $share)
else
# message if `ping` failed
echo "ping to $ip failed"
fi
done < file.txt
산출:
ping to 127.0.0.1 successful
domain: localhost
share: aaa
share: nnn
share: cvcc
ping to 8.8.8.8 successful
domain: dns
share: bbb
share: tttt
share: rrrr
ping to failedip failed
답변3
for n in ${A} ${B} ; do
이것은 당신이 원하는 것을하지 않습니다. 인덱스 없이 배열을 가져오는 것은 인덱스 0에 있는 요소를 가져오는 것과 동일하므로 ${A}
과 ${A[0]}
같습니다 B
. 루프는 $n
각 값을 하나씩 설정 하므로 ${A[0]}
첫 번째 반복을 수행한 다음 ${B[0]}
두 번째 반복을 수행합니다.
${n[0]}
배열이 아닌 등에도 동일하게 적용되므로 ${n[1]}
거기에는 아무것도 없고 다른 모든 것은 설정되지 않은 것뿐입니다.${n[2]}
$n
${n[0]}
이제 Bash는 실제로 2D 배열을 처리하지 않지만 다음을 사용하여 구조를 뒤집을 수 있습니다.
ips=(127.0.0.1 8.8.8.8)
names=(localhost dns)
for i in "${!ips[@]}"; do
if ping -c3 "${ips[i]}"; then
echo "host ${names[i]-"(unknown")} is up"
fi
done
하지만 어쨌든 데이터를 별도의 파일에 저장해야 할 수도 있습니다.
Zsh에서는 데이터 구조 및 루프와 관련된 모든 것이 다를 수 있으며 IIRC ksh도 Bash보다 더 나은 데이터 구조 지원을 제공합니다.