문자열의 마지막 3 자만 인쇄하는 명령


30

나는 알고 cut명령은 첫 번째 인쇄 할 수 있습니다 n문자열의 문자를하지만 어떻게 마지막 선택하는 n문자를?

가변 문자 수를 가진 문자열이있는 경우 문자열의 마지막 세 문자 만 어떻게 인쇄 할 수 있습니까? 예.

필요한 "무제한"출력은 "ted"
"987654"출력은 "654"입니다.
"123456789"출력은 "789"입니다.

답변:


52

아무도 분명한 대답을하지 않은 이유는 무엇입니까?

sed 's/.*\(...\)/\1/'

… 또는 약간 덜 명백한

grep -o '...$'

물론 두 번째 문자는 3 자 미만의 줄이 사라지는 단점이 있습니다. 그러나 질문은이 사건의 행동을 명시 적으로 정의하지 않았습니다.


6
또는grep -o '.\{3\}$'
Avinash Raj

3
또는echo "unlimited" | python -c "print raw_input()[-3:]"
Kiro

8
@Kiro 또는 "echo unlimited" | java -jar EnterpriseWordTrimmer.jar이지만 문자 조작을 위해 더 무거운 언어를 가져올 필요는 없다고 생각합니다.
wchargin

11
@WChargin 당신은 잊었다java -server -Xms300M -Xmx3G -XX:+UseParallelGC -cp /path/to/all/the/jars/ -Dinput.interactive=false -Dinput.pipe=true -Dconfig.file=/path/to/config/last-three-letters.cfg -jar ...
hjk

6
grep -o -P '.{0,3}$'줄이 3 자 미만인 경우에도 마지막 3자를 인쇄합니다. -P버팀대를 피할 필요가 없습니다.
Raghu Dodda

43

단순하게 유지-꼬리

문자 수를 계산하기 위해 정규식이나 두 개 이상의 프로세스가 필요하지 않습니다. 파일 의 마지막 을 표시하는 데 자주 사용되는
명령 에는 옵션 ( )이 있으며 이는 올바른 도구 인 것 같습니다.tail-c--bytes

$ printf 123456789 | tail -c 3
789

(쉘에있을 때 mikeserv의 대답과 같은 방법을 사용하는 것이 좋습니다 tail. 프로세스 시작을 저장하지 않기 때문입니다 .)

실제 유니 코드 문자?

이제 마지막 세 문자 를 요구 합니다 . 이 답변이 제공하는 것은 아닙니다. 마지막 3 바이트를 출력합니다 !

각 문자가 1 바이트 인 tail -c한 작동합니다. 이 사용할 수 있도록 문자 집합 인 경우 ASCII, ISO 8859-1또는 변형.

공통 UTF-8형식 과 같이 유니 코드 입력이있는 경우 결과가 잘못되었습니다.

$ printf 123αβγ | tail -c 3
�γ

이 예 UTF-8에서 그리스 문자 인 alpha, beta 및 gamma는 2 바이트 길이입니다.

$ printf 123αβγ | wc -c  
9

이 옵션 -m은 최소한 실제 유니 코드 문자를 계산할 수 있습니다.

printf 123αβγ | wc -m
6

마지막 6 바이트는 우리에게 마지막 3 문자를 줄 것입니다 :

$ printf 123αβγ | tail -c 6
αβγ

따라서 tail일반 문자 처리를 지원하지 않으며 시도조차하지 않습니다 (아래 참조) : 가변 크기 줄은 처리하지만 가변 크기 문자는 처리하지 않습니다.

이런 식으로하자 : tail문제의 구조가 해결하기에는 옳지 만 데이터 종류에는 틀리다.

GNU coreutils

더 찾고, 그것은 그대 GNU의로 coreutils, 기본 도구 모음이 좋아하는 것으로 나타났다 sed, ls, tailcut, 아직 완전히 국제화되지 않습니다. 주로 유니 코드 지원에 관한 것입니다.
예를 들어, cut문자 지원을 위해 꼬리 대신 여기를 사용하는 것이 좋습니다. 바이트 또는 문자에 대한 작업 옵션이 있습니다 -c( --bytes) 및 -m(--chars ).

2013 년 버전 기준 으로 그 -m/ 만 구현되지 않았습니다!--chars
cut (GNU coreutils) 8.21

보낸 사람 info cut:

`-c CHARACTER-LIST'
`--characters=CHARACTER-LIST'
     Select for printing only the characters in positions listed in CHARACTER-LIST.  
     The same as `-b' for now, but internationalization will change that.


참조이 대답캔은 UTF-8로`컷 -c`를 (`--characters`)를 사용하지? .


2
실제로, 현재 로케일이 UTF-8 인코딩을 지정하는 한 대부분의 다른 답변은 유니 코드를 잘 처리하는 것처럼 보입니다. 당신과 glenn jackman의 cut기반 솔루션 만 보이지 않습니다.
Ilmari Karonen

@IlmariKaronen 사실, 힌트 주셔서 감사합니다. 추가 세부 정보를 편집했습니다.
Volker Siegel

1
POSIX tail는 문자가 아닌 바이트를 처리하도록 명시 적으로 지정합니다 . 한 번은 문자를 선택할 수있는 새로운 옵션을 추가하기위한 패치를 만들었지 만 병합 된 적이 없다고 생각합니다 :-/
Martin Tournoij

다음과 같은 파일 모드에서 작동하지 않습니다tail -c3 -n10 /var/log/syslog
Suncatcher

@Suncatcher 나는 시도했지만 효과가있었습니다. 당신이 보는 문제는 무엇입니까? 당신의 명령 tail -c3 -n10 /var/log/syslog은 마지막 10 줄을 요구하며, 그것은 저에게 효과적입니다. 옵션을 사용하고 -c3그 후에 충돌하는 옵션을 사용 -n10합니다. 나중 옵션이 우선합니다.
Volker Siegel

36

텍스트가이라는 쉘 변수 STRING에있는 경우 bash, zsh또는 mksh쉘 에서이를 수행 할 수 있습니다 .

printf '%s\n' "${STRING:(-3)}"

또는

printf '%s\n' "${STRING: -3}"

또한 구문이 시작되는 ksh93과 함께 작동하는 이점이 있습니다.

요점은 :에서와 분리되어야 -하며 그렇지 않으면 ${var:-default}Bourne 쉘 의 연산자 가됩니다 .

zsh또는 yash쉘 에서 동등한 구문은 다음과 같습니다 .

printf '%s\n' "${STRING[-3,-1]}"

2
더 많은 정보를 검색 할 수 있도록 어떤 종류의 구문 / 작업이 호출됩니까?
Tulains Córdova

6
이를 Substring Expansion 이라고 합니다. 일종의 매개 변수 확장 입니다. 일반적인 형식은 $ {parameter : offset : length} 이지만 length 필드는 선택 사항입니다 (보시다시피 위의 답변에서 생략되었습니다). DopeGhoti도 작성했습니다 수 ${STRING:(-3):3}합니다 (지정 길이 , 필드) ${STRING: -3}(사이 공백 :과를 -) 또는 ${STRING: -3:3}.
G-Man, 'Reinstate

이 경우 길이를 지정하는 3것은 "마지막 문자에서 세 번째 문자의 세 문자를 포함하여"를 요구하기 때문에 다소 무섭습니다. "마지막 문자에서 세 번째 문자부터 세 번째 문자까지"와 같은 실제 작업에서 동일한 작업이됩니다 , 포함한".
DopeGhoti


11

문자열이 변수에 있으면 다음을 수행 할 수 있습니다.

printf %s\\n "${var#"${var%???}"}"

그러면 $varlike 의 값에서 마지막 세 문자가 제거됩니다 .

${var%???}

... 그리고 나서 $var모든 것의 머리에서 벗겨 지지만 막 벗겨진 것 :

${var#"${var%???}"}

이 방법에는 단점과 단점이 있습니다. 밝은면에서는 POSIX로 완벽하게 이동할 수 있으며 모든 현대 쉘에서 작동해야합니다. 또한, 만약 $var3 자 이상을 포함하지 않습니다 아무것도 하지만 후행 \newline가 인쇄됩니다. 당신이 경우 다시, 원하는 이 경우 인쇄, 당신은 같은 추가 단계가 필요하다

last3=${var#"${var%???}"}
printf %s\\n "${last3:-$var}"

그런 식으로 3 바이트 이하의 바이트를 포함하는 $last3경우에만 비어 $var있습니다. 그리고 비어 있거나 비어있는 경우 $var로만 대체 되며 우리는 그것을 설정했기 때문에 그렇지 않습니다 .$last3$last3unsetunset


꽤 깔끔한 +1입니다. 따로 : printf형식 문자열을 인용하지 않는 이유는 무엇입니까?
jasonwryan

${VARNAME:(-3)}(가정 bash)을 사용하지 않습니까?
DopeGhoti

1
설명해 주셔서 감사합니다. (나에게) 조금 이상해 보일지라도 말이된다.
jasonwryan

1
@DopeGhoti-그것은 거의 내가 결코 가정하지 않기 때문입니다. 이것은 bashPOSIX 호환성을 주장하는 다른 쉘 에서도 잘 작동합니다 .
mikeserv

3
@odyssey-문제는 불행히도 여기서 언급 한 최신 POSIX 호환 쉘 중 하나 csh아닙니다 . POSIX 쉘 사양은 이후 에 모델링되었으며 , 전통적인 Bourne 스타일 쉘과 자체 조합을 통해 모델링되었습니다 . 모두 통합 의 우수한 작업 제어 기능과 기존의 Bourne의-스타일 'I / O 리디렉션을. 또한 위에서 설명한 문자열 조작 개념과 같은 것들도 추가했습니다. 이것은 내가 아는 한 전통적인 방식 으로는 작동하지 않을 것 입니다. 미안합니다. kshcshkshcshcsh
mikeserv

7

당신은 이것을 할 수 있지만 이것은 조금 ... 과도합니다 :

for s in unlimited 987654 123456789; do
    rev <<< $s | cut -c 1-3 | rev
done 
ted
654
789

3

utf-8 문자열에 대한 방탄 솔루션 :

utf8_str=$'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' # привет

last_three_chars=$(perl -CAO -e 'print substr($ARGV[0], -3)' "$utf8_str")

또는 사용하십시오 :

last_three_chars=$(perl -MEncode -CO -e '
  print substr(decode("UTF-8", $ARGV[0], Encode::FB_CROAK), -3)
' "$utf8_str")

잘못된 데이터 처리를 방지합니다.

예:

perl -MEncode -CO -e '
  print substr(decode("UTF-8", $ARGV[0], Encode::FB_CROAK), -3)
' $'\xd0\xd2\xc9\xd7\xc5\xd4' # koi8-r привет

다음과 같이 출력합니다 :

utf8 "\xD0" does not map to Unicode at /usr/lib/x86_64-linux-gnu/perl/5.20/Encode.pm line 175.

로케일 설정에 의존하지 않습니다 (예 :로 작동 LC_ALL=C). Bash, sed, grep, awk, rev이 같은 필요합니다LC_ALL=en_US.UTF-8

일반적인 해결책 :

  • 바이트 받기
  • 인코딩 감지
  • 바이트를 문자로 디코딩
  • 캐릭터 추출
  • 문자를 바이트로 인코딩

uchardet으로 인코딩을 감지 할 수 있습니다 . 관련 프로젝트 도 참조하십시오 .

Perl의 Encode , Python 2.7의 코덱 으로 디코딩 / 인코딩 할 수 있습니다

:

utf-16le 문자열에서 마지막 세 문자를 추출하고이 문자를 utf-8로 변환

utf16_le_str=$'\xff\xfe\x3f\x04\x40\x04\x38\x04\x32\x04\x35\x04\x42\x04' # привет

chardet <<<"$utf16_le_str"  # outputs <stdin>: UTF-16LE with confidence 1.0

last_three_utf8_chars=$(perl -MEncode -e '
    my $chars = decode("utf-16le", $ARGV[0]);
    my $last_three_chars = substr($chars, -3);
    my $bytes = encode("utf-8", $last_three_chars);
    print $bytes;
  ' "$utf16_le_str"
)

참조 : perlunitut , 파이썬이 유니 코드 HOWTO


echo방탄 출처는 무엇입니까?
mikeserv

@ mikeserv decode/encode는 내 방탄 소스입니다. 내 대답을 정리했습니다.
Evgeny Vereshchagin

바이트 세트가 다른 문자 세트의 다른 문자를 반영 할 수 있기 때문에 이는 올바르게 작동하도록 로케일 설정에 따라 다릅니다. LC_ALL=C매우 "멍청한"설정이기 때문에 "작동" 하지만 UTF-8 문자열을 SHIFT-5로 전달하거나 SHIFT-5 문자열을 KOI8 등으로 전달하려고하면 중단 될 수 있습니다.
Martin Tournoij

@Carpetsmoker, 감사합니다. 당신의 의견을 설명해 주시겠습니까? 나는 그것이 perl -CAO -e 'print substr($ARGV[0], -3)'잘 작동 한다고 생각 합니다. A@ARGV 요소는 UTF-8로 인코딩 된 문자열 O이어야하고 STDOUT은 UTF-8입니다.
Evgeny Vereshchagin

당신에게 할당에 대해 이야기하는 것 같습니다utf8_str
Evgeny Vereshchagin

1

"expr"또는 "rev"를 사용하는 것은 어떻습니까?

@ G-Man이 제공하는 것과 비슷한 대답 : expr "$yourstring" : '.*\(...\)$' grep 솔루션과 동일한 단점이 있습니다.

잘 알려진 트릭은 "cut"과 "rev"를 결합하는 것입니다. echo "$yourstring" | rev | cut -n 1-3 | rev


rev솔루션처럼 많이 보이는 글렌 잭맨의
제프 쉘러

당신은 맞아 @Jeff_Schaller : 나는 glenn의 하나를 놓쳤다 :-(
gildux

0

다음을 사용하여 문자열의 크기를 가져옵니다.

size=${#STRING}

그런 다음 마지막 n 문자의 하위 문자열을 가져옵니다.

echo ${STRING:size-n:size}

예를 들면 다음과 같습니다.

STRING=123456789
n=3
size=${#STRING}
echo ${STRING:size-n:size}

줄 것이다 :

789


-1

문자열에 공백이 있으면 printf가 작동하지 않습니다.

공백이있는 문자열의 코드 아래

str="Welcome to Linux"
echo -n $str | tail -c 3

Nux


음, 작동 printf하지 않으면, 당신은 매우 잘못 하고있는 것입니다.
Kusalananda

1
@Kusalananda : Saurabh가 보여주는 명령에 따라 printf $str( printf "$str"또는 대신 printf '%s' "$str") 시도했습니다 . 그리고, 예, printf $str있습니다 매우 잘못. ( echo -n $str더 좋은 것은 아닙니다).
G-남자가 말한다 '분석 재개 모니카'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.