쉘 스크립팅에서 문자열의 처음 두 문자를 추출하는 방법은 무엇입니까?


123

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

USCAGoleta9311734.5021-120.1287855805

다음을 추출하고 싶습니다.

US

6
모두 감사합니다. 나는 'cut -c1-2'를 사용하게되었고, 솔직히 'cut'이있는 줄도 몰랐다. 명령 줄에서 꽤 경험이 많았지 만 배울 것이 많다고 말하고 싶습니다.
Greg

1
@Greg, cut은 별도의 프로세스로 실행된다는 점에 유의하십시오. 내 대답에 함께 게시 한 내부 bash 솔루션보다 느릴 것입니다. 방대한 데이터 세트를 처리하지 않는 한 아무런 차이가 없지만 염두에 두어야합니다.
paxdiablo

실제로 편집하십시오. 이 코드 줄은 보고서 당 약 50,000 번 실행될 것이라고 생각합니다. 그래서 나는 내부 Bash 방법을 사용할 수 있습니다-당신이 말했듯이 필요한 자원을 많이 절약 할 수 있습니다.
Greg

답변:


180

아마도 가장 효율적인 방법은 bash셸을 사용하는 경우 (주석에 따르면) 매개 변수 확장의 하위 문자열 변형을 사용하는 것입니다.

pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}" ; echo "${short}"
US

이것은 short의 처음 두 문자로 설정 됩니다 long. long2 자 미만인 경우 short동일합니다.

이 in-shell 방법은 프로세스 생성 오버 헤드가 없기 때문에 일반적으로 많은 작업을 수행 할 경우 (예 : 보고서 당 50,000 번) 더 좋습니다. 외부 프로그램을 사용하는 모든 솔루션은 이러한 오버 헤드를 겪게됩니다.

또한 최소 길이 를 보장 하려면 다음과 같이 미리 패딩 할 수 있습니다.

pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}" ; echo "${short}"
A.

이렇게하면 길이가 2 자 미만이면 오른쪽에 마침표가 채워집니다 (또는 만들 때 사용 된 문자를 변경하는 것만으로도 다른 것 tmpstr). 이것이 필요한지는 확실하지 않지만 완전성을 위해 넣을 것이라고 생각했습니다.


하지만 외부 프로그램 (예 : bash사용할 수 없는 경우)으로이를 수행하는 방법에는 여러 가지가 있으며, 그중 일부는 다음과 같습니다.

short=$(echo "${long}" | cut -c1-2)
short=$(echo "${long}" | head -c2)
short=$(echo "${long}" | awk '{print substr ($0, 0, 2)}'
short=$(echo "${long}" | sed 's/^\(..\).*/\1/')

처음 두 개 ( cuthead)는 한 줄 문자열에 대해 동일합니다. 기본적으로 둘 다 처음 두 문자 만 돌려줍니다. 그들은 cut각 줄의 처음 두 문자를 제공하고head 의 처음 두 문자를 제공하고 전체 입력의 처음 두 문자를

세 번째는 awk하위 문자열 함수를 사용하여 처음 두 문자를 추출하고 네 번째는 sed캡처 그룹 ( ()및 사용 \1)을 사용 하여 처음 두 문자를 캡처하고 전체 줄을 이들로 바꿉니다. 둘 다 비슷합니다 cut. 입력에서 각 줄의 처음 두 문자를 전달합니다.

입력 한 내용이 한 줄이라는 것이 확실하다면 그 어느 것도 문제가되지 않으며 모두 동일한 효과를가집니다.


차라리 사용하는 것 printf '%s'대신 echo: 문자열에 이상한 문자가있는 경우 stackoverflow.com/a/40423558/895245 다음 POSIX의 경우는 집착 head -cPOSIX하지 않습니다, cut -c그리고 awk substr이다 sed \1확실하지.
치로 틸리郝海东冠状病六四事件法轮功

1
@CiroSantilli 新疆 改造 中心 996ICU 六四 事件 printf를 사용하면 추가 프로그램이 필요하지 않습니다. 내 대답을 참조하십시오 .
bschlueter 19

60

가장 쉬운 방법은

${string:position:length}

이것이 at에서 $length부분 문자열을 추출하는 곳$string$position 합니다.

이것은 bash 내장이므로 awk 또는 sed가 필요하지 않습니다.


이것은 짧고 달콤하며 가장 쉬운 방법으로 부분 문자열을 얻는 것입니다.
ani627

34

몇 가지 좋은 답변을 받았으며 Bash 내장을 직접 사용했지만 질문 sedawk했고 ( 거의 ) 아무도 그에 기반한 솔루션을 제공하지 않았기 때문에 다음을 제공합니다.

echo "USCAGoleta9311734.5021-120.1287855805" | awk '{print substr($0,0,2)}'

echo "USCAGoleta9311734.5021-120.1287855805" | sed 's/\(^..\).*/\1/'

awk하나는 매우 명확한다고하지만, 여기에 대한 설명이다 sed하나

  • "s /"대체
  • "^"줄의 시작 부분에서 시작하여 "."문자가 뒤에 오는 문자 ".."중 두 문자의 "()"그룹 0 회 이상 "*"반복 (일부 특수 문자를 이스케이프하려면 백 슬래시가 필요함)
  • "/"로 첫 번째 (이 경우에만) 그룹의 내용 (여기서 백 슬래시는 일치하는 하위 표현식을 참조하는 특수 이스케이프 임)
  • 완료 "/"

1
awk 문자열은 인덱스 1에서 시작하므로 substr($0,1,2).
Isaac

8

에있는 경우 다음 bash과 같이 말할 수 있습니다.

bash-3.2$ var=abcd
bash-3.2$ echo ${var:0:2}
ab

이것은 당신이 필요로하는 것일 수 있습니다…


가장 쉽고 가장 간단한 대답! 마법처럼 일
알로하

7

그냥 grep :

echo 'abcdef' | grep -Po "^.."        # ab

내 필요에 맞습니다. -P옵션을 제거하여 더 짧게 만들 수 있습니다 . 모든 정규식은 그 패턴을 이해할 것입니다.
datashaman

6

다음을 사용할 수 있습니다 printf.

$ original='USCAGoleta9311734.5021-120.1287855805'
$ printf '%-.2s' "$original"
US

5

콜름 — 파일에서 열 제거

처음 두 문자를 남기려면 3부터 시작하는 열을 제거하십시오.

cat file | colrm 3

4

참 늦었지만 여기 있습니다

sed 's/.//3g'

또는

awk NF=1 FPAT=..

또는

perl -pe '$_=unpack a2'

2

셸 스크립팅을 사용하고 비 -posix 확장 (예 : bashisms)에 의존하지 않으려면 grep, sed, cut, awk 등과 같은 외부 도구를 분기 할 필요가없는 기술을 사용할 수 있습니다. 스크립트를 덜 효율적으로 만드십시오. 사용 사례에서 효율성과 posix 이식성이 중요하지 않을 수 있습니다. 그러나 그것이 (또는 좋은 습관처럼) 경우 다음 매개 변수 확장 옵션 방법을 사용하여 쉘 변수의 처음 두 문자를 추출 할 수 있습니다 .

$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab

이것은 "가장 작은 접두사"매개 변수 확장 을 사용하여 처음 두 문자 (이 ${var#??}부분)를 제거한 다음 "가장 작은 접미사"매개 변수 확장 ( ${var%부분)을 사용하여 원본에서 처음 두 문자를 제외한 모든 문자열을 제거합니다. 값.

이 방법은 이전 에 "Shell = Check if variable starts with #"질문에 대한 이 답변 에서 설명했습니다 . 이 답변은 또한 여기에 원래 질문에 적용되는 것과 약간 다른 컨텍스트에서 사용할 수있는 몇 가지 유사한 매개 변수 확장 방법을 설명합니다.


최고의 답변은 위에 있어야합니다. 포크도, 바 시즘도 없습니다. 대시와 같은 작은 쉘에서도 작동합니다.
exore

1

시스템이 다른 셸 (아님 bash)을 사용하고 있지만 시스템 에이 있는 경우 변수 를 호출 하여 bash의 고유 한 문자열 조작을 계속 사용할 수 있습니다 .bashbash

strEcho='echo ${str:0:2}' # '${str:2}' if you want to skip the first two characters and keep the rest
bash -c "str=\"$strFull\";$strEcho;"

이것은 주 답변 과 동일한 방법을 사용하며 bash아직 사용하지 않는 경우 에만 호출 합니다.
palswim

불행히도 이것은 다른 프로세스를 호출하는 모든 오버 헤드를 동반하지만 때로는 그 오버 헤드가 단순성과 친숙 함만큼 중요하지 않습니다.
palswim

1

재미를 위해 몇 가지를 추가하겠습니다. 비록 너무 복잡하고 쓸모가 없지만 언급되지 않았습니다.

head -c 2 <( echo 'USCAGoleta9311734.5021-120.1287855805')

echo 'USCAGoleta9311734.5021-120.1287855805' | dd bs=2 count=1 status=none

sed -e 's/^\(.\{2\}\).*/\1/;' <( echo 'USCAGoleta9311734.5021-120.1287855805')

cut -c 1-2 <( echo 'USCAGoleta9311734.5021-120.1287855805')

python -c "print(r'USCAGoleta9311734.5021-120.1287855805'[0:2])"

ruby -e 'puts "USCAGoleta9311734.5021-120.1287855805"[0..1]'

0
perl -ple 's/^(..).*/$1/'

당신은 그 문자열을 에코하는 것을 잊었습니다.
Chas. Owens


0

이것이 당신의 뒤입니까?

my $string = 'USCAGoleta9311734.5021-120.1287855805';

my $first_two_chars = substr $string, 0, 2;

심판 : substr


1
그 / 그녀가 가능성이 쉘에서이 호출되어야 함을 주어, 더 나은 형태가 될 것이다perl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'
차스합니다. Owens
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.