쉘 명령 출력의 문자 수

쉘 명령 출력의 문자 수

명령 출력에서 ​​문자 수를 계산해야 하는 스크립트를 작성 중입니다.단계.

예를 들어, 이 명령의 출력 길이가 10자이므로 이 명령을 사용하면 readlink -f /etc/fstab결과가 반환되어야 합니다 .10

이는 다음 코드를 사용하여 변수를 저장함으로써 달성할 수 있습니다.

variable="somestring";
echo ${#variable};
# 10

불행하게도 명령으로 생성된 문자열에 동일한 수식을 사용하면 작동하지 않습니다.

${#(readlink -f /etc/fstab)};
# bash: ${#(readlink -f /etc/fstab)}: bad substitution

먼저 출력을 변수에 저장하면 이 작업을 수행할 수 있다는 것을 알고 있습니다.

variable=$(readlink -f /etc/fstab);
echo ${#variable};

하지만 추가 단계를 제거하고 싶습니다.

가능합니까? Almquist 셸(sh)과 호환되는 내장 유틸리티나 표준 유틸리티를 사용하는 것이 가장 좋습니다.

답변1

그리고GNU 표현:

$ expr length + "$(readlink -f /etc/fstab)"
10

GNU에는 다음 인수가 , ...와 같은 연산자 인 경우에도 문자열로 처리되도록 하는 +특수 기능이 있습니다 .exprexprmatchlength+

위의 코드는 출력에서 ​​모든 후행 개행 문자를 제거합니다. 이 문제를 해결하려면:

$ expr length + "$(readlink -f /etc/fstab; printf .)" - 2
10

결과가 차감됩니다.2끝에 개행 문자와 추가한 문자가 있기 때문입니다 readlink..

유니코드 문자열의 경우 expr문자 수 대신 문자열 길이를 바이트 단위로 반환하므로 작동하지 않는 것 같습니다(참조654호선)

$ LC_ALL=C.UTF-8 expr length ăaa
4

따라서 다음을 사용할 수 있습니다.

$ printf "ăaa" | LC_ALL=C.UTF-8 wc -m
3

앞쪽:

$ expr " $(readlink -f /etc/fstab; printf .)" : ".*" - 3
10

명령 대체 앞의 공백은 명령이 그것으로 시작하는 문자열에서 충돌하는 것을 방지하므로 -3을 빼야 합니다.

답변2

쉘 내장 기능을 사용하여 이 작업을 수행하는 방법을 잘 모르겠습니다(비록 Gnouc은) 그러나 표준 도구가 도움이 될 수 있습니다.

  1. wc -m이를 사용하여 문자 수를 계산할 수 있습니다 . 불행하게도 마지막 개행 문자도 계산되므로 먼저 이를 제거해야 합니다.

    readlink -f /etc/fstab | tr -d '\n' | wc -m
    
  2. 물론 당신은 사용할 수 있습니다awk

    readlink -f /etc/fstab | awk '{print length($0)}'
    
  3. 아니면 펄

    readlink -f /etc/fstab | perl -lne 'print length'
    

답변3

나는 보통 이렇게 합니다:

$ echo -n "$variable" | wc -m
10

명령을 실행하려면 다음과 같이 조정합니다.

$ echo -n "$(readlink -f /etc/fstab)" | wc -m
10

이 방법은 두 단계를 하나의 라이너로 결합한다는 점을 제외하면 2단계에서 수행한 것과 유사합니다.

답변4

이는 작동 dash하지만 대상 변수가 완전히 비어 있거나 설정되지 않아야 합니다. 그렇기 때문에 실제로는명령 - $l첫 번째 명령에서 명시적으로 지웠습니다.

l=;printf '%.slen is %d and result is %s\n' \
    "${l:=$(readlink -f /etc/fstab)}" "${#l}" "$l"

산출

len is 10 and result is /etc/fstab

그게 전부 쉘 내장 기능입니다(물론 제외 readlink). 하지만 현재 쉘에서 이를 평가한다는 것은 len을 얻기 전에 할당해야 함을 의미합니다. 이것이 바로 %.s형식 문자열의 첫 번째 인수를 무시 하고 목록 끝에 arg 리터럴 값을 printf추가한 이유입니다. printf.

그리고 eval:

l=$(readlink -f /etc/fstab) eval 'l=${#l}:$l'
printf %s\\n "$l"

산출

10:/etc/fstab

동일한 결과에 가까워질 수 있지만 첫 번째 명령의 변수 출력 대신 표준 출력으로 표시됩니다.

PS4='${#0}:$0' dash -cx '2>&1' "$(readlink -f /etc/fstab)"

...어디에 써있는지...

10:/etc/fstab

...현재 쉘의 변수에 값을 할당하지 않고 파일 설명자 1에.

관련 정보