쉘에 JavaScript의 "split ()"과 같은 것이 있습니까?


18

split()JavaScript 를 사용 하여 문자열을 배열로 나누는 것은 매우 쉽습니다 .

쉘 스크립트는 어떻습니까?

내가 이것을하고 싶다고 가정 해보십시오.

$ script.sh var1_var2_var3

사용자가 그러한 문자열 var1_var2_var3을 script.sh에 제공하면 스크립트 안에서 문자열 을 다음과 같은 배열로 변환합니다.

array=( var1 var2 var3 )
for name in ${array[@]}; do
    # some code
done

1
무엇을 shell당신과 함께 사용하는 bash당신이 할 수있는IFS='_' read -a array <<< "${string}"
— gwillie

perl그렇게 할 수도 있습니다. "순수한"쉘은 아니지만 매우 일반적입니다.
— Sobrique

@Sobrique 또한 "순수한"쉘의 기술적 정의를 모르지만 node.js가 있습니다.
— emory

나는 '아마 기본적으로 내 리눅스 박스에 설치'에 대한 연구 경향과 사소한 : 걱정하지 않는다
— Sobrique

답변:


24

Bourne / POSIX와 유사한 쉘에는 split + glob 연산자가 있으며 목록 컨텍스트에서 매개 변수 확장 ( $var, $-...), 명령 대체 ( $(...)) 또는 산술 확장 ( $((...))) 을 남겨 둘 때마다 호출됩니다 .

실제로, for name in ${array[@]}대신 에 실수로 호출했습니다 for name in "${array[@]}". (실제로, 연산자를 실수로 호출하면 많은 버그와 보안 취약점이 생길 수 있습니다.)

해당 연산자는 $IFS특수 매개 변수 (스플릿 할 문자를 알려주기 위해 (공백, 탭 및 개행은 특별한 처리를 받음)) 부품 -f을 비활성화 ( set -f) 또는 활성화 ( set +f)하는 옵션으로 glob구성됩니다.

또한 Sin $IFS은 분리기 (POSIX 쉘 $IFS) 에서 원래 ( S본인 Bourne 쉘 에서) 사용 되었지만 문자는 구분 기호 또는 종결$IFS 자로 표시되어야 합니다 (아래 예 참조).

분할 _:

string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator

for i in "${array[@]}"; do # loop over the array elements.

separator 와 delimiter 의 차이점을 보려면 다음을 시도하십시오.

string='var1_var2_'

그것은 그것을 ( var1그리고 var2여분의 빈 요소가 아닌) 로 나눌 것 입니다.

따라서 JavaScript와 비슷하게 만들려면 split()추가 단계가 필요합니다.

string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator

(공백 은 JavaScript와 같이 1을 0이 아닌 ) 요소 $string로 나눕니다 .split()

특수 처리 탭, 공백 및 개행 수신을 보려면 다음을 비교하십시오.

IFS=' '; string=' var1  var2  '

(당신은 얻을 곳 var1과 var2함께)

IFS='_'; string='_var1__var2__'

당신이 얻을 경우 : '', var1, '', var2, ''.

참고 것을 zsh쉘하지 않습니다 암시 같은 스플릿 + 글로브 운영자 호출되지 않는 이상 sh또는 ksh에뮬레이션. 거기에서 명시 적으로 호출해야합니다. $=string분할 부분, $~stringglob 부분 ( $=~string둘 다) 및 분리자를 지정할 수있는 split 연산자도 있습니다.

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

또는 빈 요소를 보존하려면 :

array=("${(@s:_:)string}")

이 점에 유의 s을위한 분할 하지 구분 (과 또한 $IFS, 알려진 POSIX의 비 적합성 zsh). split()빈 문자열이 0이 아닌 1 요소로 분리된다는 점 에서 JavaScript와 다릅니다 .

에 주목할만한 차이 $IFS-splitting은 즉 ${(s:abc:)string}온 분할 abc로하면서, 문자열 IFS=abc, 그에 분할 것 a, b또는 c.

로 zsh하고 ksh93, 공백, 탭 또는 개행 문자 수신하는 특별 대우는 그들을 두 배로하여 제거 할 수 있습니다 $IFS.

역사적으로, Bourne 쉘 (조상 또는 현대 POSIX 쉘)은 항상 빈 요소를 제거했습니다. 또한 기본값이 아닌 값으로 $ @의 분할 및 확장과 관련된 많은 버그가있었습니다 $IFS. 예를 IFS=_; set -f; set -- $@들어와 같지 않습니다 IFS=_; set -f; set -- $1 $2 $3....

정규 표현식으로 나누기

이제 split()정규 표현식으로 나눌 수있는 JavaScript에 더 가까운 무언가를 위해서는 외부 유틸리티를 사용해야합니다.

POSIX tool-chest awk에는 확장 정규 표현식으로split 분할 할 수 있는 연산자가 있습니다 (JavaScript에서 지원하는 Perl과 유사한 정규 표현식의 하위 집합입니다).

split() {
  awk -v q="'" '
    function quote(s) {
      gsub(q, q "\\" q q, s)
      return q s q
    }
    BEGIN {
      n = split(ARGV[1], a, ARGV[2])
      for (i = 1; i <= n; i++) printf " %s", quote(a[i])
      exit
    }' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"

이 zsh쉘은 Perl 호환 정규 표현식 ( zsh/pcre모듈에서)을 기본적으로 지원 하지만 문자열을 분할하기 위해이를 사용하는 것은 비교적 번거 롭습니다.


탭, 공백 및 줄 바꿈으로 특별한 처리가 필요한 이유가 있습니까?
— cuonglm

1
@cuonglm, 일반적으로는 구분 기호가 공백이 아닌 구분 기호의 경우, 공백 때 단어 분할 할 (분할에처럼 $PATH에 :반대로), 당신은 일반적으로 빈 요소를 보존하려는. Bourne 쉘에서 모든 문자는 특수 처리를 받았으며 ksh공백 문자 (공백, 탭 및 개행 문자 만)가 특수 문자로 처리되도록 변경되었습니다.
— Stéphane Chazelas

최근에 추가 된 Bourne 쉘 노트는 저를 놀라게했습니다. 그리고 완료를 위해, zsh문자열 처리 에 대한 메모를 두 개 이상의 문자로 포함 ${(s:string:)var}해야합니까? 추가하면 내 답변을 삭제할 수 있습니다 :)
— cuonglm

1
"$ IFS의 S는 구분자가 아니라 구분자를위한 것"이라는 의미는 무엇입니까? 나는 역학을 이해하고 후행 구분 기호는 무시하지만 구분 기호 가 아니라 구분 기호를S 나타냅니다 . 적어도 내 배쉬 매뉴얼이 말한 것입니다.
— terdon

@terdon $IFS은 Bourne 쉘에서 왔으며 separator 였습니다 . ksh는 이름을 변경하지 않고 동작을 변경했습니다. split+globzsh 또는 pdksh를 제외하고는 더 이상 스트레스를 나누지 않는다고 강조합니다 .
— Stéphane Chazelas

7

예, 사용 IFS하고로 설정하십시오 _. 그런 다음을 사용 read -a하여 배열에 저장합니다 ( -r백 슬래시 확장 기능 끄기). 이것은 bash에만 해당됩니다. ksh와 zsh는 구문이 약간 다른 유사한 기능을 가지고 있으며 일반 sh에는 배열 변수가 없습니다.

$ r="var1_var2_var3"
$ IFS='_' read -r -a array <<< "$r"
$ for name in "${array[@]}"; do echo "+ $name"; done
+ var1
+ var2
+ var3

보낸 사람 man bash:

읽다

- 이름

단어는 0부터 시작하여 배열 변수 aname의 순차적 색인에 지정됩니다. aname은 새로운 값이 지정되기 전에 설정되지 않습니다. 다른 이름 인수는 무시됩니다.

IFS

확장 후 단어 분리 및 내장 명령 읽기를 사용하여 행을 단어로 분할하는 데 사용되는 내부 필드 구분 기호입니다. 기본값은`` ''입니다.

참고 read첫 번째 줄 바꿈에서 멈 춥니 다. 통과 -d ''하는 read것을 방지하기 위해,하지만 그 경우에, 때문에에 마지막에 여분의 줄 바꿈이있을 것이다 <<<연산자. 수동으로 제거 할 수 있습니다.

IFS='_' read -r -d '' -a array <<< "$r"
array[$((${#array[@]}-1))]=${array[$((${#array[@]}-1))]%?}

$r줄 바꿈 문자 나 백 슬래시가 포함되어 있지 않다고 가정합니다 . 또한 최신 버전의 bash셸 에서만 작동합니다 .
— Stéphane Chazelas

@ StéphaneChazelas 좋은 지적. 예, 이것은 문자열의 "기본"사례입니다. 나머지는 모두가 당신의 포괄적 인 답변을 찾아야합니다. 의 버전에 관해서는 bash, read -abash는 4, 오른쪽 도입?
— fedorqui

1
죄송 합니다만, <<<최근에 추가 된 것으로 생각 bash되었지만 2.05b (2002) 이후에 있었던 것 같습니다. read -a그것보다 더 오래되었습니다. <<<에서 유래 zsh에서 지원됩니다 ksh93뿐만 아니라 (그리고 mksh 및 YASH)하지만 read -abash는 특정 (그것의 인 -A경우 ksh93, YASH 및 zsh을에서).
— Stéphane Chazelas

@ StéphaneChazelas 이러한 변경이 언제 발생했는지 쉽게 찾을 수있는 방법이 있습니까? 릴리스 파일을 파헤 치지 말고 "쉬운"이라고 말하면 페이지가 모두 표시됩니다.
— fedorqui

1
그 변경 로그를 봅니다. 또한 zsh에는 3.1.5까지의 히스토리가있는 git 저장소가 있으며 메일 링리스트는 변경 사항 추적에도 사용됩니다.
— Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.