한 변수에서 다른 변수로 특정 행을 전송하고 싶습니다. 나는 이것을 시도했지만 작동하지 않습니다.
c="1.apple
2.banna
3.peach"
read "Please choose fruit [1-3]:" t
a=$c | awk "NR==$t"
echo "You choose: $a"
내 실수는 무엇입니까?
답변1
사용이 문자열은 리디렉션됩니다.<<<
~와 함께명령 대체$()
그리고 잊지 마세요변수 주위에 큰따옴표 추가:
a=$(awk "NR==$t" <<< "$c")
답변2
첫 번째:
read "Please choose fruit [1-3]:" t
...작동하지 않습니다. shellbuildin에 프롬프트 문자열을 제공하려는 것처럼 보이지만 read
옵션 read
이 제공되지 않는 한 첫 번째 인수를 변수 이름으로 해석하여 stdin에서 읽은 줄의 값을 할당합니다.
read -p "Please choose fruit [1-3]:" t
...은 많은 쉘에서 지원되는 옵션이며 원하는 작업에 더 가깝습니다.
즉, 이전에 값을 분할하는 방법을 식별하지 않은 한 단일 구분 할당에 여러 값을 쌓아서는 안 됩니다. 이 작업을 수행할 때:
var=' some list of things '
쉘은 결국 이를 다음과 같이 구문 분석합니다.
\0 some list of things \0
...단일 값에 단일 이름을 할당합니다. 많은 쉘은 명명된 배열과 같은 고급 형태의 분리를 제공하지만 모든 POSIX 쉘은 $@
함수 컨텍스트별로 쉽게 정의할 수 있는 최소한 하나의 배열, 즉 쉘 배열을 제공합니다. 명명된 배열을 제공하는 다양한 구현은 종종 $@
명명된 배열에 대한 셸 배열 동작을 모방하기도 합니다.
따라서 다음과 같이 이러한 모든 개별 값을 단일 문자열에 할당하는 대신:
set apple banana peach
다음과 같이 각 개별 값을 숫자로 개별적으로 처리하여 효과를 확인할 수 있습니다.
printf %s\\n "$1"
...인쇄:
apple
참고 - 9보다 큰 값을 사용하려면 참조를 중괄호로 묶는 것이 좋습니다."${10}"
다음과 같이 고유 문자열 수를 확인할 수 있습니다 "$#"
.
printf %d\\n "$#"
...인쇄...
3
별도의 문자열 목록에서 이러한 많은 문제를 해결할 수 있습니다. 예를 들면 다음과 같습니다.
printf %s\\n "$@"
...인쇄:
apple
banana
peach
...또는 단일 연결 문자열로 사용됩니다. 예를 들면 다음과 같습니다.
printf %s\\n "$*"
...여기서 개별 배열 값 문자열은 쉘 변수에 포함된 첫 번째 문자에 연결됩니다 $IFS
. 따라서 배열의 각 문자열에 기본값이 있으면 $IFS
그 사이에 단일 문자열을 사용하여 다음 문자열에 연결됩니다. 예를 들어 위 명령은 다음을 인쇄합니다.<space><tab><newline>
<space>
apple banana peach
...하지만 그렇게 한다면:
IFS='fruit sucks'; printf %s\\n "$*"
...다음과 같이 인쇄됩니다.
applefbananafpeach
명명된 배열 확장을 구현하는 대부분의 셸은 유사한 구문을 사용하지만 배열 주소를 지정하는 다양한 방법은 이름과 연결되어야 합니다. 배열 할당은 일반적으로 다음과 같습니다.
array=( apple banana peach )
...또는...
array[0]=apple array[1]=banana array[2]=peach
"$1"
명명된 배열은 일반적으로 "$#"
, , 와 "$@"
비교 하여 작동 하며 이전에 언급한 과 사이 의 관계가 계속 적용됩니다."$*"
"${array[1]}"
"${#array[@]}"
"${array[@]}"
"${array[*]}"
"$*"
"$IFS"
"${array[*]}"
가치관을 올바르게 정의하면 문제를 처리하기가 더 쉬워집니다.
set apple banana peach; n=0
{ for a do printf "$((n+=1)).:\t%s\n" "$a"; done
printf "Please choose fruit [1-$#]: "; read t
} <>/dev/tty >&0 &&
[ "0$((!${#t}))" -lt "0${t##*[!0-9]*}" ] &&
eval 'printf "You choose: %s\n" "${'"$t"}\"
일부는 위의 사용을 비웃을 수 있지만 eval
여기서 사용하는 것은 많은 사람들이 원하는 것보다 안전하지 않습니다."${array[$t]}"
(이름이 지정된 배열을 사용하여 이를 수행하는 한 가지 방법은 다음과 같습니다.)왜냐하면 처음에 문자열로 구문 분석한 후 "${array[$t]}"
두 번째로 평가된다는 의미이기 때문입니다. $t
최소한 1과 숫자만 포함되어 있고 0보다 큰지 확인하기 위해 위에서 했던 것처럼 테스트할 필요가 없습니다.(또는 가장 작은 명명된 배열 인덱스의 쉘 구현은 무엇입니까)어느 상황이든 예상치 못한 결과가 발생할 수 있습니다.