쉘에 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.

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

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  '

(당신은 얻을 곳 var1var2함께)

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.