변수, 문자열 또는 배열의 크기를 바이트 단위로 얻는 방법은 무엇입니까?

변수, 문자열 또는 배열의 크기를 바이트 단위로 얻는 방법은 무엇입니까?

예를 들어, 배열을 만든다면:

$ array1=($(find /etc -mindepth 1 -maxdepth 1 -type d))
$ echo ${#array[@]}
105
$ for each in ${array1[@]}; do echo $each ; done
/etc/alternatives
/etc/apache2
/etc/apparmor
/etc/apparmor.d
... so on and so forth, you get the idea.

bash를 사용하여 길이가 아닌 바이트 단위로 크기를 인쇄하는 방법이 있습니까? 아니면 문자 수에 따라 수동으로 계산해야 합니까?

나는 다음과 같은 것을 시도했습니다 :

$ var2="a"
$ echo $var2 | wc -c
2
$ echo $var2
a

하지만 다음은 이렇습니다.

$ var2=""
$ echo $var2 | wc -c
1
$ echo $var2

공백변수의 존재는 1바이트인 것으로 보입니다. 하지만 1글자의 글자수는 2글자입니다.

$ echo a | wc -c
2
$ echo a | wc -m
2
$ echo aa | wc -c
3
$ echo aa | wc -m
3

개행 문자는 1바이트이고 각 문자도 1바이트인 것처럼 보입니다. 배열을 얻고, 새 줄 수를 세고, 문자 수를 세고, 계산을 하는 것은 어려운 것 같습니다. 제가 너무 생각하고 있는 건가요? 아니면 정확한 수치를 알려줄 수 있는 유틸리티가 있나요?

답변1

array1=($(find /etc -mindepth 1 -maxdepth 1 -type d))

find이는 목록을 얻기 위해 출력에 대해 분할+글로브를 수행하기 때문에 잘못된 것입니다 (어쨌든 find없는 출력은 -print0사후 처리가 불가능합니다). (4.4+)의 올바른 구문은 bash다음과 같습니다.

readarray -td '' array1 < <(find /etc -mindepth 1 -maxdepth 1 -type d -print0)

또는 zsh:

array1=(/etc/*(ND/))

존재하다echo $var | wc -c

출력에서 바이트를 계산하고 있습니다 echo. $var이는 여러 가지 이유로 바이트 수가 아닙니다.

  • 인용하는 것을 잊었 $var으므로 분할+글로브의 영향을 받습니다.
  • echo전환을 해보세요. 일부 구현은 \x이스케이프 시퀀스를 확장하고 일부는 값을 -n옵션 으로 취급합니다.
  • 마지막으로 echo개행 문자가 출력에 추가됩니다( -n일부 구현에서는 건너뛸 수 있음 echo).

여기서 wc바이트 수를 계산하려면 다음을 수행합니다.

printf %s "$var" | wc -c

에서는 다음으로 확장합니다 bash.${#var}수치변수에서. 바이트 수로 만들려면 로케일을 C로 수정하면 됩니다.

LC_ALL=C
echo "${#var}"

배열의 모든 요소에 대한 바이트 길이의 합을 얻으려면 요소를 연결하여 결과 문자열의 길이를 얻을 수 있습니다.

printf %s "${array[@]}" | wc -c

또는:

IFS=
concat="${array[*]}"
LC_ALL=C
echo "${#concat}"

zsh를 사용하면 다음을 수행할 수 있습니다.

() { set -o localoptions +o multibyte
  echo ${#${(j[])array}}
}

여기서 매개변수 확장 플래그는 전역을 사용하는 j[sep]대신 배열의 요소를 연결하는 데 사용됩니다 . 로케일을 수정하는 대신 get 옵션을 비활성화할 수 있습니다."${array[*]}"$IFSCmultibyte특징바이트(이 작업은 로컬 익명 함수에서 수행됩니다).

바이트와 ​​문자 간의 차이를 확인하려면 멀티바이트 인코딩을 문자 맵(예: UTF-8, GB18030, BIG5...)으로 사용하고 멀티바이트 인코딩 문자에 사용하는 로캘이 필요합니다. a일반적으로 1바이트로 인코딩되므로 차이를 볼 수 없습니다. 예를 들어 인코딩은 UTF-8에서는 3바이트이고 ISO8859-15에서는 1바이트입니다.

예( zsh):

$ a=($'\xe2\x82\xac20' '$25' $'\xa420')
$ locale charmap
UTF-8
$ typeset -p a
typeset -a a=( €20 '$25' $'\M-$20' )
$ printf %s "${a[@]}" | wc -c
11
$ printf %s "${a[@]}" | wc -m
8
$ echo ${#${(j[])a}}
9
$ (){set -o localoptions +o multibyte; echo ${#${(j[])a}}}
11

문자 맵이 ISO8859-15인 로케일로 전환하는 경우:

$ locale charmap
ISO-8859-15
$ a=($'\xe2\x82\xac20' '$25' $'\xa420')
$ typeset -p a
typeset -a a=( â¬20 '$25' €20 )
$ printf %s "${a[@]}" | wc -c
11                           
$ printf %s "${a[@]}" | wc -m
11
$ echo ${#${(j[])a}}
11
$ (){set -o localoptions +o multibyte; echo ${#${(j[])a}}}
11

ISO8859-15는 단일 바이트 문자 인코딩이므로특징바이트거기.

추가 자료:


bash(또는 zsh)와 유사 wc -m하지만 bash(또는 zsh)도 문자로 디코딩할 수 없는 바이트를 각각 한 문자로 계산합니다.

관련 정보