
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에서 배열 길이는 $#array
csh와 동일하며 매개변수 확장 연산자를 중첩할 수 있으므로 ${#${#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 -n
bash 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)
그러나 가독성이 떨어지며 나중에 다른 스크립트에서 사용하기 위해 복사할 수 있는 함수에 특수 작업이 식별되고 캡슐화되는 약간 더 긴 스크립트를 선호합니다.