쉘 스크립트에서 문자열 조작을 사용하여 문자열의 마지막 문자 삭제


187

문자열의 마지막 문자를 삭제하고 싶습니다.이 작은 스크립트를 시도했습니다.

#! /bin/sh 

t="lkj"
t=${t:-2}
echo $t

하지만 "lkj"를 인쇄합니다. 제가 뭘 잘못하고 있습니까?

답변:


115

POSIX 셸에서 구문 ${t:-2}은 다른 것을 의미합니다. tif t는 set 의 값으로 설정되고 null이 아닌 값으로 확장 되고 그렇지 않으면 value로 확장됩니다 2. 매개 변수 확장으로 단일 문자를 자르려면 원하는 구문은 다음과 같습니다.${t%?}

그의 주 ksh93, bash또는 zsh, ${t:(-2)}또는 ${t: -2}(공간주의) 이다 문자열 확장 법적 그러나 그들은 (끝에서의 위치에이 개 문자를 시작하는 문자열을 반환하기 때문에 당신이 원하는 것을 아마하지 않습니다 즉, 그것은 제거 첫 번째 문자 i의를 문자열 ijk).

자세한 내용은 Bash Reference Manual의 Shell Parameter Expansion 섹션을 참조하십시오.


4
'%'뒤에 숨겨진 마법이 무엇인지 설명하고 싶습니까? ?
afraisse

8
@afraisse ${parameter%word}는 가장 짧은 접미사 패턴 일치를 제거합니다.wordman bash
steeldriver

3
이것은 Bash 4.1.2에서 잘 작동합니다 : CentOS / RHEL 6.x를 사용하는 사람들을위한 $ {t %?}
Joey T

185

bash위의 4.2, 당신은 할 수 있습니다 :

${var::-1}

예:

$ a=123
$ echo "${a::-1}"
12

이전 버전 bash(예 : bash 3.2.5OS X)의 경우 콜론 사이와 뒤에 콜론을 두어야합니다.

${var: : -1}

13
이것은 bash버전 4.2-alpha 이상에서 작동하며 , 내가 액세스 할 수있는 버전이 너무 나쁩니다. :-/
hjk

2
@iamaziz : bash changelog에서 음수 길이는 ${var:offset:lenght}에 추가되었습니다 bash 4.2. OSX가에 대한 자체 패치를 추가했을 수도 있습니다 bash.
cuonglm

1
@cuonglm 어느 쪽도 작동하지 않습니다 : /
iamaziz

1
Mac에서는 작동하지 않습니다.
shinzou

1
MACster 여러분, Russ의 답변을보십시오
P i

67

OR을 n사용하지 않는 행에서 마지막 문자 를 제거합니다 .sedawk

> echo lkj | rev | cut -c (n+1)- | rev

예를 들어 다음을 사용하여 마지막 문자 one character를 삭제할 수 있습니다 .

> echo lkj | rev | cut -c 2- | rev

> lk

에서 rev맨 :

설명
rev 유틸리티는 지정된 파일을 모든 행의 문자 순서를 반대로하여 표준 출력으로 복사합니다. 파일을 지정하지 않으면 표준 입력을 읽습니다.

최신 정보:

문자열의 길이를 모르는 경우 다음을 시도하십시오.

$ x="lkj"
$ echo "${x%?}"
lk

62

sed를 사용하면

sed 's/.$//'

그러면 단일 에코echo ljk | sed 's/.$//'입니다.
이것을 사용하여 1 줄 문자열은 모든 크기가 될 수 있습니다.


10
일반적인 경우, 그것은하지 않습니다 문자열의 마지막 문자 삭제 ,하지만 마지막 문자 문자열의 모든 줄을 .
Stéphane Chazelas

44

쉘에 따라 몇 가지 옵션 :

  • POSIX : t=${t%?}
  • 시내: t=`expr " $t" : ' \(.*\).'`
  • zsh / yash : t=${t[1,-2]}
  • bash / zsh : t=${t:0:-1}
  • ksh93 / bash / zsh / mksh : t=${t:0:${#t}-1}
  • ksh93 / bash / zsh / mksh : t=${t/%?}
  • ksh93 : t=${t/~(E).$/}
  • es : @ {t=$1} ~~ $t *?

모든 것이 마지막 문자 를 제거해야 하지만 일부 구현 (멀티 바이트 문자를 지원하지 않는 구현)은 마지막 바이트를 대신 제거합니다 (멀티 바이트 인 경우 마지막 문자가 손상 될 수 있음) ).

expr변형을 가정 $t한 개 이상의 개행 문자로 끝나지 않습니다. 결과 문자열이 될 수있을 테니까요 경우에도 0이 아닌 종료 상태를 반환합니다 0(또는 000심지어 -0일부 구현과 함께). 문자열에 유효하지 않은 문자가 포함되어 있으면 예기치 않은 결과가 발생할 수도 있습니다.


좋고 철저한! 그러나 ... 나는 모든 쉘이 POSIX를 지원한다고 가정하므로 모든 사람이 가장 이식성이 뛰어납니다. 가장 작은 문자 수!
Russ

@Russ t=${t%?}는 Bourne이 아니지만 요즘 Bourne 쉘을 발견하지 못할 것입니다. ${t%?}그래도 다른 모든 것들에서 작동합니다.
Stéphane Chazelas

생선 껍질 옵션이 없습니다! 아마도 ksh93보다 요즘 아마도 더 인기가 있습니다.
rien333

@ rien333. 인터페이스가 약간 안정화 될 때까지 기다립니다. fish진행중인 작업입니다. stringQ & A 당시에 는 내장 을 도입 한 2.3.0이 릴리스되지 않았습니다. 내가 테스트하고있는 버전으로, 당신은 string replace -r '(?s).\z' '' -- $t(그리고 그들이 그것을 바꾸고 싶을 것이라고 기대할 것입니다, 그들은 PCRE에 전달하는 플래그를 변경해야합니다) 또는 더 복잡한 것들. 또한 줄 바꿈 문자를 제대로 처리하지 못하기 때문에 줄 바꿈 문자도 변경하려고한다는 것을 알고 있습니다.
Stéphane Chazelas

POSIX 답변으로 상향 조정되었습니다. Bash 3.2.57 (1) 작업 완료
Avindra Goolcharan

26

가장 휴대 가능하고 가장 짧은 대답은 거의 확실합니다.

${t%?}

이것은 bash, sh, ash, dash, busybox / ash, zsh, ksh 등에서 작동합니다.

구식 쉘 매개 변수 확장을 사용하여 작동합니다. 특히, glob 패턴과 %일치하는 가장 작은 일치하는 매개 변수 접미사를 제거 하도록 지정합니다 (예 : 모든 문자).t?

"작은 접미사 패턴 제거"를 참조하십시오 여기에 A (훨씬)에 대한 자세한 설명과 많은 배경. 또한 man bash"매개 변수 확장"에서 쉘에 대한 문서 (예 :)를 참조하십시오 .


당신은 제거하기를 원한다면 사이드 참고로, 첫 번째 대신 문자를, 다음을 사용 ${t#?}하기 때문에, #대신 다시 (접미사)의 문자열 (접두사)의 전면에서 일치.

또한 주목할 가치가있는 것은 %#가지고 %%있고있는 ##버전 이며, 가장 짧은 버전이 아닌 주어진 패턴 의 가장 긴 버전 과 일치합니다 . 모두 ${t%%?}${t##?}이 경우 자신의 하나의 연산자로 동일한 기능을 수행 할 것입니다,하지만 (그래서 쓸모없는 여분의 문자를 추가하지 마십시오). 주어진 ?패턴이 단일 문자와 만 일치 하기 때문 입니다. A의 믹스 *일부 비 와일드 카드로 물건은 더 흥미있어 %%하고 ##.

매개 변수 확장을 이해하거나 최소한 그것들의 존재와 그것을 찾는 방법을 아는 것은 많은 맛의 쉘 스크립트를 작성하고 해독하는데 매우 유용합니다. 음 ... 그들은 ... 때문에 매개 변수 확장은 종종 많은 사람들에게 비밀 쉘 부두 모양 이다 (당신이 "매개 변수 확장"을 찾기 위해 알고있는 경우에 아주 잘 설명하지만) 비밀 쉘 부두를. 쉘에 갇혀있을 때 공구 벨트에 확실히 좋습니다.


짧고 달콤하며 MacOS와 Linux 모두에서 작동합니다!
dbernard

18
t=lkj
echo ${t:0:${#t}-1}

0에서 문자열 길이 -1까지의 하위 문자열을 얻습니다. 그러나이 빼기는 bash에만 적용되며 다른 쉘에서는 작동하지 않습니다.

예를 들어 dash파싱조차 할 수 없습니다

echo ${t:0:$(expr ${#t} - 1)}

예를 들어, 우분투에 /bin/sh있다dash


15

head마지막 문자를 제외한 모든 문자를 인쇄 할 수도 있습니다 .

$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin

그러나 불행히도 일부 버전 head에는 주요 -옵션이 포함되어 있지 않습니다 . headOS X와 ​​함께 제공 되는 경우입니다.


5

정규 표현식을 사용하면 충분합니다.

n=2
echo "lkj" | sed "s/\(.*\).\{$n\}/\1/"

5

약간의 개선. 둘 이상의 문자를 제거하기 위해 여러 물음표를 추가 할 수 있습니다. 예를 들어 변수에서 마지막 두 문자를 제거하려면 $SRC_IP_MSG다음을 사용할 수 있습니다.

SRC_IP_MSG=${SRC_IP_MSG%??}

4

순수한 bash의 가능한 사용법을 완료하려면 다음을 수행하십시오.

#!/bin/bash

# Testing substring removal
STR="Exemple string with trailing whitespace "
echo "'$STR'"
echo "Removed trailing whitespace: '${STR:0:${#STR}-1}'"
echo "Removed trailing whitespace: '${STR/%\ /}'"

첫 번째 구문은 문자열에서 하위 문자열을 가져 오고 구문은 다음과 같습니다. 두 번째 구문의 경우 '줄 끝에서'를 의미 하는 부호를 확인하고 구문은
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}

그리고 여기 위에서 언급 한 두 가지 짧은 형태가 있습니다.

echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"

여기서 가장 짧은 일치 패턴 (여기서 이스케이프 된 공간 '\' 으로 표시되는 PARAMETER 의 끝 -여기서 STR로% 표시됨)을 의미 하는 부호를 다시 알 수 있습니다.


1

명령 행이나 셸 스크립트에서 php 를 사용할 수도 있습니다 . 때로는 수술 파싱에 유용합니다.

php -r "echo substr('Hello', 0, -1);" 
// Output hell

배관으로 :

echo "hello" | php -r "echo substr(trim(fgets(STDIN)), 0, -1);"
// Output hell

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.