bash 배열 인덱스 번호의 문자열 길이를 어떻게 찾을 수 있나요?

bash 배열 인덱스 번호의 문자열 길이를 어떻게 찾을 수 있나요?

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

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

ncurses대상 시스템에 tput이나 기타 "멋진" 형식 유틸리티가 없기 때문에 bash 내에 있어야 합니다 . 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}zsh에서 bash에 의해 복사되었습니다(종종 ksh를 통해 간접적으로). {1..$expansion}zsh 또는 ksh에서는 작동하지만 bash에서는 작동하지 않습니다.

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


bash를 사용해야 한다면, 지금처럼 두 단계로 수행하는 것이 아마도 최대한 좋을 것입니다.

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

또한 bash(불행히도 배열 디자인 bash가 복사된 ksh에서와 같이)에서 배열은 실제로 배열이 아니라 키가 양의 정수이고 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 이상이 필요합니다)


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

답변2

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

답변3

편집하다:사과드립니다. @ilkkachu가 친절하게 알려줬듯이 변수의 길이를 얻는 가장 간단한 방법은 ${#variable}외부 도구를 사용하는 것이 아니라 를 사용하는 것입니다. 이 답변을 무시하십시오. 곧 삭제하겠습니다. 부끄러워요!

숫자의 자릿수를 결정하려면 숫자의 밑수 10에 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)

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

관련 정보