bash 배열 인덱스 번호의 문자열 길이를 찾는 방법은 무엇입니까?

bash 배열 인덱스 번호의 문자열 길이를 찾는 방법은 무엇입니까?

Bash에서 함수가 길이를 알 수 없는 간단한 배열을 생성한다고 가정합니다. 배열이 변환되어 화면에 인쇄됩니다. 각 행 옆에는 선택할 수 있는 작은 인덱스 번호가 있습니다. 공간은 제한되어 있었고, 프레젠테이션은 완벽해야 했으며, 도구 세트도... 뭐, 흠잡을 곳이 없었다고 말하고 싶습니다.

어떻게 찾을 수 있어?문자열 길이~의인덱스 번호 자체(포맷 목적으로) 이것은 배열의 값이 아닙니다. 예를 들어, 배열에 334,345개 항목이 있는 경우(마지막 항목 인쇄 사용 echo ${hugearray[334344]}) 그것이 6내가 찾고 있는 것입니다.

ncurses대상 시스템에 tput이나 기타 "멋진" 포맷 유틸리티가 없기 때문에 bash에 머물러야 합니다. 자기 자신만 공격합니다.

${#WORD[@]}총 항목 수를 알려주며 이를 얻기 위해 몇 가지 기본 구성을 구축합니다.

$〉pkglist+=($(brew list -1)) # ← I'm testing on a Mac.
$〉printf "%s\n" ${pkglist[@]}
automake
xquartz

$〉echo ${#pkglist[@]}
68

$〉indexlength=${#pkglist[@]}
$〉echo ${#indexlength}
2

작동하지만 완전히 우아하지는 않습니다.변호하자면 저는 개발자가 아닙니다.하지만 나는 이 작업을 수행하는 더 좋고 쉬운 방법, 중첩된 간접 참조 또는 다른 bash 부두가 이미 있었으면 좋겠습니다. 하지만일반 물건실제 데이터에 어떤 영향을 미치는지 충분히 혼란스럽기 때문에 후회하기 전에 물어보는 것이 가장 좋다고 생각합니다(대상 시스템에는 루트 계정만 있습니다). 당신은 있나요?

감사해요!

답변1

Macos를 사용한다면 zsh에 액세스할 수 있어야 하므로 bash를 사용할 필요가 없습니다.

zsh에서 배열 길이는 $#arraycsh와 같으며 매개변수 확산 연산자를 중첩할 수 있으므로 ${#${#array}}1을 수행하여 배열 길이의 소수 표현 길이를 얻을 수 있습니다.

$ a=(qwe asdasd qewqw)
$ () {printf "%${#${#a}}d %s\n" "${@:^a}"} {1..$#a}
1 qwe
2 asdasd
3 qweqe
$ a=( {a..m} )
$ () {printf "%${#${#a}}d %s\n" "${@:^a}}" {1..$#a}
 1 a
 2 b
 3 c
 4 d
 5 e
 6 f
 7 g
 8 h
 9 i
10 j
11 k
12 l
13 m

모든 array=(...), array+=(...){x..y}bash에 의해 zsh에서 복사되었습니다(보통 ksh를 통해 간접적으로). {1..$expansion}zsh 또는 ksh에서는 작동하지만 bash에서는 작동하지 않습니다.

배열 ${a:^b}압축 연산자와 () {code} args익명 함수는 여전히 zsh에만 적용됩니다.


bash를 꼭 사용해야 한다면, 여러분처럼 두 단계로 수행하는 것이 아마도 가장 좋을 것입니다.

$(((l=${#array[@]}),SHLVL[l=\${#l}],l))배열 인덱스의 지연 평가에 의존하여 하나의 확장에서 이 작업을 수행할 수 있지만 이는 가독성에 도움이 되지 않으며 미래에도 보장되지 않을 수 있습니다.

또한 bash에서(ksh에서와 같이 bash의 배열 디자인은 불행하게도 복사되었습니다) 배열은 실제로 배열이 아니라 연관 배열에 더 가깝습니다. 키는 양의 정수이고 0부터 시작합니다(대부분의 다른 껍질과 달리 1)

bash-5.1$ a=( [5]=123 [123]=qwe [4567]=asd )
bash-5.1$ typeset -p a
declare -a a=([5]="123" [123]="qwe" [4567]="asd")
bash-5.1$ echo "${#a[@]}"
3

3배열의 요소 수이지만 필요한 가장 높은 키 값은 아닙니다.

bash-5.1$ keys=("${!a[@]}")
bash-5.1$ echo "${keys[@]: -1}"
4567

따라서 정렬된 키와 값을 인쇄하려면 다음과 같은 것이 필요합니다.

printarray() {
  local -n arr="$1"
  local -a keys=("${!arr[@]}")
  local highest_key="${keys[@]: -1}"
  local key_width="${#highest_key}"
  local key
  for key in "${keys[@]}"; do
    printf '%*d %s\n' "$key_width" "$key" "${arr[key]}"
  done
}
bash-5.1$ printarray a
   5 123
 123 qwe
4567 asd

(Macos의 고대 bash에서는 작동하지 않습니다. local -nbash 4.3 이상이 필요합니다)


¹은 ${#$#array}Korn 스타일 연산자를 사용하여 처음부터 제거한 후 길이로 처리되므로 작동하지 않습니다 ${#${$#array}}.$$array${var#pattern}

답변2

당신이 말했듯이 이것은 일종의 BASH 마법일 수 있습니까? - 추가 변수는 없지만
: $((${#pkglist[*]}-1)); echo ${#_}; $_는 디버깅 문제를 일으킬 수 있습니다. - 긴 스크립트

답변3

편집하다:@ilkkachu가 친절하게도 알려줬듯이 변수의 길이를 알아내는 가장 쉬운 방법은 ${#variable}외부 도구를 사용하는 것보다 를 사용하는 것입니다. 이 답변은 무시해 주세요. 곧 삭제하겠습니다. 나는 정말 창피하다!

숫자의 자릿수를 확인하려면 숫자에 1을 더한 로그에 1을 더한 다음 소수 부분을 빼면 됩니다. 하지만 이진 계산기에는 bc이를 수행하는 편리한 기능이 있습니다.

echo "length(334344)" | bc

필요에 따라 6을 인쇄합니다. 인수가 length정수가 아닌 경우 소수점 쉼표 없이 실제 자릿수를 계산합니다(즉, length(3.4560)5가 됩니다).

echo큰따옴표 안에 Bash 변수 확장을 사용하여 Bash 변수를 삽입하려면 다음을 수행하세요.

x=334344
echo "length($x)" | bc

쉽게 호출하기 위해 이것을 함수로 작성할 수 있습니다.

function num_digits {
#determine hoy many digits has a number
#param number
    local number="$1"
    echo "length($number)" | bc
}

그런 다음 다음과 같이 사용하십시오.

lendigits=$(num_digits 334344)

또는 변수를 사용하십시오.

x=334344
lendigits=$(num_digits $x)

노트:Linux 배포판에 아직 설치되어 있지 않은 경우 bc배포판의 패키지 관리자를 사용하여 추가할 수 있습니다.

노트 2:물론 함수 대신 표현식을 직접 사용할 수도 있습니다.

x=334344
lendigits=$(echo "length($x)" | bc)

그러나 가독성이 낮기 때문에 나중에 다른 스크립트에서 사용하기 위해 복사할 수 있는 특수 작업이 식별되고 함수에 캡슐화되는 약간 더 긴 스크립트를 선호합니다.

관련 정보