쉘 명령 출력의 문자 수

쉘 명령 출력의 문자 수

명령 출력의 문자 수를 계산하는 데 필요한 스크립트를 작성 중입니다.한 걸음.

예를 들어 해당 명령의 출력 길이가 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:

$ 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

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

  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의 첫 번째 인수를 무시 printf하고 다시 추가하는 이유입니다. printf의 인수 목록 끝에 있는 리터럴 값입니다 .

와 함께 eval:

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

산출

10:/etc/fstab

동일한 결과에 가까워질 수 있지만 첫 번째 명령의 변수 출력 대신 stdout에서 결과를 얻습니다.

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

...글을 쓰는 중...

10:/etc/fstab

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

관련 정보