필드 분할을 위해 언제 임시 IFS를 사용할 수 있습니까?

필드 분할을 위해 언제 임시 IFS를 사용할 수 있습니까?

Bash에서는 다음이 있다고 가정합니다 var=a.b.c..

$ IFS=. printf "%s\n" $var
a.b.c

그러나 이러한 사용법은 IFS배열을 생성할 때 적용됩니다.

$ IFS=. arr=($var)
$ printf "%s\n" "${arr[@]}"
a
b
c

물론 굉장히 편리한데, 이건 어디에 기록되는 걸까요? 다음 장을 빠르게 읽으세요.정렬또는분사Bash 문서에는 지침이 제공되지 않습니다. IFS꿰뚫어 보고단일 페이지 문서이 효과에 대한 힌트도 제공되지 않습니다.

이 작업이 언제 안정적으로 수행될 수 있는지 잘 모르겠습니다.

IFS=x do something

그리고 이는 IFS필드 분할에 영향을 미칠 것으로 예상됩니다.

답변1

기본 아이디어는 외부 명령이 실행될 때 실행 되도록 VAR=VALUE some-command설정하는 것이며 그보다 더 멋진 것은 아닙니다. 이러한 직관을 쉘 작동 방식에 대한 지식과 결합하면 대부분의 경우 올바른 답을 얻을 수 있습니다. POSIX 참조는 다음과 같습니다.VARVALUEsome-commandsome-command"쉘 명령 언어" 장의 "간단한 명령".

만약 some-command그것이라면외부 명령, VAR=VALUE some-command와 동일합니다 env VAR=VALUE some-command. VAR은(는) 환경으로 내보내지며 some-command셸의 값(또는 값 부족)은 변경되지 않습니다.

만약 some-command그것이라면기능, 그러면 VAR=VALUE some-command와 동일합니다 VAR=VALUE; some-command. 즉,할당량이 여전히 존재함함수가 반환된 후에는 변수가 환경으로 내보내지지 않습니다. 그 이유는 Bourne 쉘의 설계(및 후속 하위 호환성)와 관련이 있습니다. 함수 실행 중에 변수 값을 저장하고 복원하는 기능이 없습니다. 함수는 셸 자체에서 실행되므로 변수를 내보내지 않는 것이 좋습니다. 그러나 ksh(ATT ksh93 및 pdksh/mksh 포함), bash 및 zsh는 VAR함수 실행 중에만 설정되는 더 유용한 동작을 구현합니다(내보내기도 함). 존재하다케시function NAME …, 표준 구문을 사용하여 정의된 함수가 아닌 ksh 구문을 사용하여 함수가 정의된 경우 이 작업을 수행합니다 NAME (). 존재하다세게 때리다, 이는 POSIX 모드(runtime 사용 시)가 아닌 bash 모드에서만 수행됩니다 POSIXLY_CORRECT=1. 존재하다다루기 힘든posix_builtins, 이 옵션이 설정되지 않은 경우 이 옵션이 기본적으로 설정되어 있지 않지만 emulate sh또는 를 통해 설정할 수 있습니다 emulate ksh.

내장 함수의 경우 some-command동작은 내장 함수의 유형에 따라 달라집니다.특수 내장 기능함수처럼 동작합니다. 특수 내장 기능은 쉘 상태에 영향을 미치기 때문에(예: break제어 흐름에 영향, cd현재 디렉토리에 영향, set위치 매개변수 및 옵션에 영향을 주기 때문에) 쉘 내부에서 구현되어야 합니다.기타 내장 기능내장 기능은 단지 성능과 편의를 위한 것이며(대부분 - 예를 들어 bash 기능은 printf -v내장 기능으로만 구현할 수 있음) 외부 명령처럼 작동합니다.

별칭 확장 후에 할당이 발생하므로 if some-command는 다음과 같습니다.별명, 먼저 확장하여 무슨 일이 일어나는지 확인하세요.

모든 경우에 할당은 명령줄 자체의 변수 대체를 포함하여 명령줄을 구문 분석한 후에 수행됩니다. 그래서 과제 전에 평가가 이루어지기 때문에 var=a; var=b echo $var인쇄됩니다 . 따라서 이전 값을 사용하여 분할합니다 .a$varIFS=. printf "%s\n" $varIFS$var

모든 유형의 명령을 다루었지만 상황이 한 가지 더 있습니다.실행할 명령이 없습니다., 즉 명령에 할당(및 리디렉션도 가능)만 포함된 경우입니다. 이 경우,할당량이 여전히 존재함. VAR=VALUE OTHERVAR=OTHERVALUE와 동일합니다 VAR=VALUE; OTHERVAR=OTHERVALUE. 따라서 그 후에도 IFS=. arr=($var)여전히 IFS로 설정되어 있습니다 .. $IFS과제에서 ~를 사용할 수 arr있고 해당 과제가 이미 새로운 값을 가질 것으로 예상할 수 있으므로 IFS확장을 위해 의 새 값을 사용하는 것이 합리적입니다 $var.

간단히 말해서, 당신은 IFS사용할 수 있습니다일시적인필드 분할만 해당:

  • 새 셸 또는 하위 셸을 시작합니다(예를 들어 값에 2자 미만의 문자가 포함된 경우 다르게 동작한다는 점을 제외하면 이는 third=$(IFS=.; set -f; set -- $var; echo "$3")복잡한 접근 방식입니다 ).third=${var#*.*.}var.
  • ksh에서 with는 ksh 구문을 사용하여 정의 IFS=. some-function됩니다 .some-functionfunction some-function …
  • IFS=. some-functionBash 및 zsh에서는 호환 모드가 아닌 기본 모드에서 실행되는 한 .

답변2

@Gilles의 답변은 정말 훌륭합니다. 그는 복잡한 문제를 자세히 설명합니다.

그러나 나는 이 명령이 왜 필요한지에 대한 답을 믿습니다.

$ IFS=. printf "%s\n" $var
a.b.c

작동 방식은 간단합니다. 전체 명령줄은 다음과 같습니다.이전에 구문 분석됨실행되었습니다. 각 "단어"는 쉘에 의해 한 번 처리됩니다.
이것예를 들어 작업이 IFS=.지연됩니다.(네 번째 단계가 마지막 단계입니다):

4.- 각 변수 할당을 확장해야 합니다...

명령을 실행하기 전에 인수의 모든 확장이 먼저 처리되어 다음 실행 가능 라인을 빌드합니다.

$ IFS=. printf "%s\n" a.b.c           ## IFS=. goes to the environment.
a.b.c

명령에 인수 및 가 제공되기 전에 값은 $var"이전" IFS로 확장됩니다.a.b.cprintf"%s\n"a.b.c

평가하다

첫 번째 수준 대기 시간은 다음과 같은 방법으로 도입될 수 있습니다 eval.

$ IFS=. eval printf "'%s\n'" \$var
a
b
c

해당 행은 "IFS="를 사용하여 (처음으로) 구문 분석됩니다. 환경은 다음과 같이 설정됩니다.

$ printf '%s\n' $var

그런 다음 다시 다음과 같이 해결됩니다.

$ printf '%s\n' a b c

그리고 이것을 실행하세요:

a
b
c

(abc) 값은 $var사용 중인 IFS 값과 구분됩니다 ..

환경

복잡하고 까다로운 부분은 언제, 어떤 맥락에서 작동하는지입니다!

Giles의 답변의 첫 번째 부분은 이것을 매우 잘 설명합니다.

한 가지 추가 세부 사항이 있습니다.

이 명령을 실행할 때:

$ IFS=. arr=($var)

IFS의 가치는 현재 환경에서 유지됩니다. 예:

$ printf '<%s>  ' "${arr[@]}" "$IFS"
<a>  <b>  <c>  <.> 

IFS는 개별 명세서에 사용됩니다.

하지만 다음과 같은 경우는 피할 수 있습니다.단일 문에 대해 IFS 설정

$ IFS=. command eval arr\=\(\$var\)

$  printf '<%s>  ' "${arr[@]}" "$IFS"
<a>  <b>  <c>  < 
> 

답변3

귀하의 질문에 대해

var=a.b.c
IFS=. printf "%s\n" $var

그것은 극단적인 상황이다.

이는 macro expansion명령에서 발생하는 일 때문입니다.앞으로쉘 변수가 IFS=.설정되었습니다.

즉, $var확장되면 이전 IFS값이 활성화된 다음 IFS으로 설정됩니다 '.'.

관련 정보