개별 명령/내장 범위에 대해 사용자 정의 IFS 값을 설정하는 것이 가능하다는 것을 알고 있습니다. 개별 명세서에 대해 사용자 정의 IFS 값을 설정하는 방법이 있습니까? 분명히 그렇지 않습니다. 왜냐하면 다음에 따르면 이 작업을 시도할 때 전역 IFS 값이 영향을 받기 때문입니다.
#check environment IFS value, it is space-tab-newline
printf "%s" "$IFS" | od -bc
0000000 040 011 012
\t \n
0000003
#invoke built-in with custom IFS
IFS=$'\n' read -r -d '' -a arr <<< "$str"
#environment IFS value remains unchanged as seen below
printf "%s" "$IFS" | od -bc
0000000 040 011 012
\t \n
0000003
#now attempt to set IFS for a single statement
IFS=$'\n' a=($str)
#BUT environment IFS value is overwritten as seen below
printf "%s" "$IFS" | od -bc
0000000 012
\n
0000001
답변1
일부 쉘( 포함 bash
)에서는:
IFS=: command eval 'p=($PATH)'
( sh/POSIX 에뮬레이션이 아닌 경우 를 사용하여 bash
생략할 수 있습니다 command
.) 그러나 이는 따옴표가 없는 변수를 사용할 때도 종종 필요하며 set -f
대부분의 셸에는 로컬 범위가 없습니다.
zsh를 사용하면 다음을 수행할 수 있습니다.
(){ local IFS=:; p=($=PATH); }
$=PATH
이는 기본적으로 수행되지 않는 단어 분할을 강제하는 것입니다(변수 확장에는 와일드카드도 없으므로 sh 시뮬레이션을 제외하고는 필요하지 않습니다 zsh
).set -f
그러나 에서는zsh
$path
묶음로 $PATH
또는 구분 기호로 분할: p=(${(s[:])PATH})
또는 p=("${(s[:]@)PATH}")
빈 요소를 유지합니다.
(){...}
(또는 function {...}
)이라고 불린다.익명 함수일반적으로 로컬 범위를 설정하는 데 사용됩니다. 함수 로컬 범위를 지원하는 다른 셸의 경우 비슷한 작업을 수행할 수 있습니다.
e() { eval "$@"; }
e 'local IFS=:; p=($PATH)'
POSIX 셸에서 변수 및 옵션의 로컬 범위를 지정하려면 다음에서 제공되는 함수를 사용할 수도 있습니다.https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh. 그런 다음 다음과 같이 사용할 수 있습니다.
. /path/to/locvar.sh
var=3,2,2
call eval 'locvar IFS; locopt -f; IFS=,; set -- $var; a=$1 b=$2 c=$3'
(BTW, $PATH
위의 분할은 zsh
IFS가 필드 구분자가 아니라 필드 구분자인 다른 쉘을 제외하고는 유효하지 않습니다.)
IFS=$'\n' a=($str)
.a=1 b=2
메모 var=value cmd
:
존재하다:
var=value cmd arg
쉘은 /path/to/cmd
새로운 프로세스에서 실행되고 in cmd
및 arg
in argv[]
및 var=value
in 을 전달합니다 envp[]
. 이는 실제로 변수 할당이 아니라 환경 변수를 전달하는 것 이상입니다.처형된주문하다. Bourne 또는 Korn 쉘에서는 set -k
작성할 수도 있습니다 cmd var=value arg
.
이제 이것은 비-처형된. Bourne 쉘에서는 alone 과 마찬가지로 in이 결국 설정 var=value some-builtin
됩니다 . 이는 예를 들어 (쓸모없는)의 동작이 내장 여부에 따라 변경된다는 것을 의미합니다.var
var=value
var=value echo foo
echo
POSIX 및/또는 ksh
Bourne 동작이 다음 클래스에서만 발생하기 때문에 이를 변경했습니다.특수 내장 기능. eval
특수 내장형입니다 read
. 아니요. 특별하지 않은 내장 명령의 경우 내장 명령의 실행만 var=value builtin
설정되어 var
외부 명령을 실행할 때와 유사하게 동작합니다.
이 command
명령은 삭제하는 데 사용할 수 있습니다.특별한그 속성특수 내장 기능. POSIX가 무시하는 것은 내장 함수에 대해 eval
이는 쉘이 변수 스택을 구현해야 한다는 것을 의미합니다( 명령을 지정하거나 범위를 지정하지 않더라도). 왜냐하면 다음을 수행할 수 있기 때문 입니다 .
.local
typeset
a=0; a=1 command eval 'a=2 command eval echo \$a; echo $a'; echo $a
심지어:
a=1 command eval myfunction
사용되거나 설정되고 호출될 수 있는 함수입니다 myfunction
.$a
command eval
(AT&T는 여전히 이를 구현하지 않음) (AT&T는 여전히 구현하지 않음) ksh
(사양은 대부분 을 기반으로 함 ) 그러나 이제 이 두 가지를 제외한 대부분의 쉘은 구현하기 때문에 이는 실제로 감독이었습니다 . 다른 쉘은 다르게 동작합니다. 예를 들면 다음과 같습니다.ksh
zsh
a=0; a=1 command eval a=2; echo "$a"
하지만. 이를 지원하는 셸에서 사용하는 것이 local
로컬 범위를 구현하는 보다 안정적인 방법입니다.
답변2
Kernighan과 Pike의 "The Unix 프로그래밍 환경"에서 가져온 표준 저장 및 복원:
#!/bin/sh
old_IFS=$IFS
IFS="something_new"
some_program_or_builtin
IFS=${old_IFS}
답변3
질문의 일부 내용은 다음과 같습니다.
IFS=$'\n' a=($str)
왼쪽에서 오른쪽으로 평가되는 두 개의 개별 전역 변수 할당으로 해석됩니다.
IFS=$'\n'; a=($str)
또는
IFS=$'\n'
a=($str)
이는 전역이 수정되는 이유와 IFS
토큰이 새 값을 가진 배열 요소로 분할되는 이유를 설명합니다.$str
IFS
IFS
다음과 같이 수정 효과를 제한하기 위해 서브쉘을 사용할 수 있습니다 .
str="value 0:value 1"
a=( old values )
( # Following code runs in a subshell
IFS=":"
a=($str)
printf 'Subshell IFS: %q\n' "${IFS}"
echo "Subshell: a[0]='${a[0]}' a[1]='${a[1]}'"
)
printf 'Parent IFS: %q\n' "${IFS}"
echo "Parent: a[0]='${a[0]}' a[1]='${a[1]}'"
a
하지만 곧 수정 사항이 서브셸에만 국한된다는 사실을 알게 될 것입니다 .
Subshell IFS: :
Subshell: a[0]='value 0' a[1]='value 1'
Parent IFS: $' \t\n'
Parent: a[0]='old' a[1]='values'
다음으로 다음 솔루션을 사용하여 IFS를 저장/복원할 수 있습니다.이 이전 답변local IFS
@msw를 사용하거나 함수 내부를 사용해 보세요.제안을 따르세요@helpermethod로. 그러나 곧 모든 종류의 문제에 직면하게 될 것입니다. 특히 스크립트 호출의 잘못된 동작에 강력해야 하는 라이브러리 작성자라면 더욱 그렇습니다.
- 처음에 설정되어 있지 않으면
IFS
어떻게 되나요 ? set -u
(일명 )을 사용하여 실행하면set -o nounset
어떻게 되나요 ?- 읽기 전용으로 설정 하면
IFS
어떻게 되나요declare -r IFS
? trap
재귀 및/또는 비동기 실행(예: 핸들러) 을 처리하기 위해 저장/복원 메커니즘이 필요한 경우 어떻게 해야 합니까?
IFS를 저장/복원하지 마십시오. 대신 임시 수정을 고수하세요.
변수 수정을 단일 명령, 내장 또는 함수 호출로 제한하려면
IFS="value" command
.여러 변수를 특정 문자로 나누어 읽으려면(
:
아래 예와 같이) 다음을 사용하십시오.IFS=":" read -r var1 var2 <<< "$str"
배열을 읽으려면 다음을 사용하십시오(대신 다음을 수행하십시오
array_var=( $str )
):IFS=":" read -r -a array_var <<< "$str"
변수 수정의 효과를 서브셸로 제한합니다.
쉼표로 구분된 배열 요소를 출력하려면 다음을 수행하십시오.
(IFS=","; echo "${array[*]}")
문자열로 캡처하려면 다음을 수행하십시오.
csv="$(IFS=","; echo "${array[*]}")"
답변4
이 명령의 경우:
IFS=$'\n' a=($str)
대안적인 해결 방법이 있습니다. 첫 번째 할당( IFS=$'\n'
)에 실행할 명령(함수)을 지정하는 것입니다.
$ split(){ a=( $str ); }
$ IFS=$'\n' split
이렇게 하면 분할이 호출되는 환경에 IFS가 배치되지만 현재 환경에는 유지되지 않습니다.
이는 또한 항상 위험한 eval 사용을 방지합니다.