구분 기호로 문자열을 나누고 N 번째 요소를 가져옵니다.


75

문자열이 있습니다.

one_two_three_four_five

나는 변수에 저장해야합니다 Atwo과 변수에 Bfour위의 문자열에서

답변:


106

필드 구분 기호로 사용 cut하고 _원하는 필드를 얻으십시오.

A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"

echoHere 문자열 대신 및 파이프를 사용할 수도 있습니다 .

A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"

예:

$ s='one_two_three_four_five'

$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two

$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four

대안이 있습니까? ksh (bsh 아님)를 사용하고 있으며 ksh : 구문 오류를 반환합니다 :`< '예기치 않은
Alex

@Alex 편집 내용을 확인하십시오.
heemayl

좋은 대답은 약간의 질문이 있습니다. 변수 "$ s"가 경로 폴더이면 어떻게됩니까? 경로 폴더를 잘라내려고하면 다음과 같이됩니다 :`$ FILE = my_user / my_folder / [file] *` $ echo $FILE my_user/my_folder/file.csv $ A="$(cut -d'/' -f2 <<<"$FILE")" $ echo $A [file]* 여기서 무슨 일이 일어나고 있는지 알고 있습니까?
Henry Navarro

1
그리고 만약 당신이 마지막 필드를 원한다면, 위치를 지정할 필요없이 또는 필드 수를 모르는 경우에 쉘 내장 만 사용하십시오 :echo "${s##*_}"
Amit Naidu

19

POSIX sh 구문 만 사용하면 매개 변수 대체 구문 을 사용 하여 한 번에 하나의 구분자를 구문 분석 할 수 있습니다 . 이 코드는 필요한 수의 필드가 있다고 가정하고 그렇지 않으면 마지막 필드가 반복됩니다.

string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"

또는 와일드 카드 확장을 사용하지 IFS않고 분리 문자로 설정 한 인용 부호없는 매개 변수 대체를 사용할 수 있습니다 (구분자가 공백이 아닌 단일 문자이거나 공백 시퀀스가 분리 문자 인 경우에만 작동 함).

string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS

이 위치 매개 변수를 방해합니다. 함수에서이 작업을 수행하면 함수의 위치 매개 변수 만 영향을받습니다.

또 다른 방법은 read내장 을 사용하는 것 입니다.

IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF

사용은 기본값으로 unset IFS돌아 오지 않습니다 IFS. 그 후에 누군가가 OldIFS="$IFS"OldIFS 내부에 null 값을 가지게됩니다. 또한 IFS의 이전 값이 기본값이며 매우 가능하고 유용하지 않다고 가정합니다. 올바른 해결책은 old="$IFS"IFS = "$ old" 를 사용하여 저장 하고 나중에 복원하는 것입니다. 또는 ... 하위 쉘을 사용하십시오 (...). 또는 더 나은 방법으로 내 대답을 읽으십시오.
sorontar

@sorontar unset IFSIFS기본값으로 복원되지 않지만 필드 분할을 기본 효과로 반환합니다. 예, 제한 사항이지만 실제로는 허용되는 제한 사항입니다. 서브 쉘의 문제점은 데이터를 가져와야한다는 것입니다. 와 함께 상태를 변경하지 않는 솔루션을 보여줍니다 read. POSIX 셸에서는 작동하지만 readhere 문서로 인해 서브 셸 에서 실행하기 때문에 Bourne 셸에서는 IIRC가 아닙니다 <<<.
Gilles

하위 쉘에 대해 att 또는 가보 쉘에서도 문제가 발생하지 않습니다. 테스트를 거친 모든 셸 (이전 본 포함)은 기본 셸에서 올바른 값을 제공합니다.
sorontar

내 길이 비슷한 경우 user/my_folder/[this_is_my_file]*어떻게됩니까? 내가이 단계들을 따를 때 얻는 것은[this_is_my_file]*
Henry Navarro

@HenryNavarro이 출력은 내 답변의 코드 스 니펫과 일치하지 않습니다. 그들 중 누구도 특별한 일을하지 않습니다 /.
Gilles

17

awk답을 찾고 싶었 으므로 여기에 하나가 있습니다.

A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')

1
그리고 마지막 부분을 원한다면-위치를 지정할 필요가 없거나 필드의 수를 모르는 경우 :awk -F_ '{print $NF}' <<< 'one_two_3_4_five'
Amit Naidu

8

가장 간단한 방법 (<<<이있는 쉘의 경우)은 다음과 같습니다.

 IFS='_' read -r a second a fourth a <<<"$string"

하나의 쉘이 불평하기 때문에 $a대신 임시 변수 를 사용합니다 $_.

전체 스크립트에서 :

 string='one_two_three_four_five'
 IFS='_' read -r a second a fourth a <<<"$string"
 echo "$second $fourth"

IFS 변경 없음, set -f(경로 확장) 문제 없음 위치 매개 변수 변경 없음 ( "$ @").


용액을 휴대용 들어 모든 IFS 변화없이 셸 (예, 모든 POSIX 포함) 또는 set -f상기 (좀더 복잡한) 히어 닥 당량을 사용

string='one_two_three_four_five'

IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_

echo "$second $fourth"

이 솔루션 (여기서는이 문서와 사용법을 사용 <<<하면 후행 줄 바꿈이 모두 제거 될 것입니다.
이는 "한
줄짜리 "가변 컨텐츠로 설계되어 있습니다.


bash 버전 4.4에서 매우 간단한 해결책이 가능합니다

readarray -d _ -t arr <<<"$string"

echo "array ${arr[1]} ${arr[3]}"   # array numbers are zero based.

많은 POSIX 셸에 배열이 없기 때문에 POSIX 셸에는 해당 사항이 없습니다.

배열이있는 쉘의 경우 다음과 같이 간단 할 수 있습니다
(attsh, lksh, mksh, ksh 및 bash에서 작동 테스트)

set -f; IFS=_; arr=($string)

그러나 변수와 옵션을 유지하고 재설정하기위한 추가 배관이 많이 있습니다.

string='one_* *_three_four_five'

case $- in
    *f*) noglobset=true; ;;
    *) noglobset=false;;
esac

oldIFS="$IFS"

set -f; IFS=_; arr=($string)

if $noglobset; then set -f; else set +f; fi

echo "two=${arr[1]} four=${arr[3]}"

zsh에서 배열은 1로 시작하며 기본적으로 문자열을 분할하지 않습니다.
따라서 zsh에서이 작업을 수행하려면 일부 변경이 필요합니다.


사용하는 솔루션은 read ... 한 영업 이익은 긴 문자열에서 76 번째와 127 번째 요소를 추출하지 않는 단순
don_crissti

물론 @don_crissti 물론, 비슷한 구성 : readarray그 상황에서 사용하기가 더 쉬울 수 있습니다.
sorontar

@don_crissti 또한 배열이있는 쉘에 대한 배열 솔루션을 추가했습니다. POSIX 쉘의 경우 배열이없는 경우 최대 127 개의 위치 매개 변수는 "간단한"솔루션이 아닙니다.
sorontar

2

zsh당신 (의 문자열을 나눌 수있는 _배열로) :

elements=(${(s:_:)string})

그런 다음 배열 색인을 통해 각 요소에 액세스하십시오.

print -r ${elements[4]}

에 있다는 사실을 양지해야합니다 zsh(달리 ksh/ bash) 배열 인덱스는 1에서 시작합니다 .


set -f첫 번째 해결책에 경고 를 추가하십시오 . ... 별표 *는?
sorontar

@sorontar-왜 내가 필요하다고 생각 set -f합니까? read/를 사용하지 않습니다 IFS. 유사한 문자열 내 해결책을 시도해보십시오 *_*_*... 또는 무엇 이건
don_crissti

zsh는 아니지만 사용자는 ksh 솔루션을 요청했기 때문에 해당 쉘에서 사용하려고 시도 할 수 있습니다. 경고는 문제를 피하는 데 도움이됩니다.
sorontar

1

파이썬 솔루션이 허용됩니까?

# python -c "import sys; print sys.argv[1].split('_')[1]" one_two_three_four_five
two

# python -c "import sys; print sys.argv[1].split('_')[3]" one_two_three_four_five
four

나쁜 나쁜 answet
Raj Kumar

0

또 다른 awk 예제; 이해하기 간단합니다.

A=\`echo one_two_three_four_five | awk -F_ '{print $1}'\`  
B=\`echo one_two_three_four_five | awk -F_ '{print $2}'\`  
C=\`echo one_two_three_four_five | awk -F_ '{print $3}'\`  
... and so on...  

변수와 함께 사용할 수도 있습니다. 다음과 같이
가정하십시오.
this_str = "one_two_three_four_five"
그러면 다음과 같이 작동합니다.
A =`echo $ {this_str} | awk -F_ '{print $ 1}'`
B =`echo $ {this_str} | awk -F_ '{print $ 2}'`
C =`echo $ {this_str} | awk -F_ '{print $ 3}'`
... 등등 ...

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