Bash에서 단어 분리를 비활성화하는 방법이 있습니까?

Bash에서 단어 분리를 비활성화하는 방법이 있습니까?

저는 bash 전문가는 아니지만 최근에 bash 스크립트를 작성하고 있는데 매번 매개변수를 인용하는 것이 정말 귀찮습니다. 이 쉘 동작을 변경할 수 있는 방법이 있습니까? 문자열이 인용되지 않은 경우에도 분할되지 않도록 하고 싶습니다.

PS - IFS를 null로 설정하면 모든 매개변수가 삭제되므로 아무런 효과가 없습니다. 내가 원하는 것은 글을 쓸 때입니다:

func1() {
    echo $1 $2 $3
}

func2() {
    echo "number of arguments func2 got: $#"
} 

func2 $(func1 firstarg "second arg is a multi word string" "third arg is also a multi word string")

다음을 인쇄합니다:

number of arguments func2 got: 3

편집, 지적해 주신 의견 덕분에: 내 예제에서는 echo를 사용하므로 코드는 func2의 인수를 참조하는지 여부에 따라 1개 또는 14개의 인수를 가져오도록 인쇄합니다. 그런데 제가 언급한 예상 결과처럼 함수에서 여러 값을 파괴하지 않고 반환할 수 있는 방법을 찾고 있습니다.

감사해요!

답변1

제목의 질문에 답하기 위해 단어 분리를 비활성화하는 방법은 IFS빈 문자열로 설정하는 것입니다.

그러나 텍스트에서 설명하는 내용은 명령 대체를 통해 전달한 후 여러 다중 단어 문자열을 구별하여 유지하는 것이 더 어렵습니다. 실제로 이 작업을 수행하는 쉬운 방법은 없습니다.

여기서 근본적인 문제는 명령 대체의 결과(~호출된 함수의 표준 출력 출력)가 단지 문자열(바이트 스트림)이고 여기에 여러 문자열을 맞추려고 한다는 것입니다. 일반적인 경우 이러한 문자열에는 임의의 내용이 포함되어 있으며 이는 매우 기본적인 문제입니다.

별로 다르지 않아요명령을 변수에 저장, 여기서는 명령 대체를 수행하고 있을 뿐입니다.


해결 방법은 구분 기호로 사용할 일부 문자를 예약하고 IFS해당 문자로 설정하는 것입니다. 기본값을 사용하면 IFS공백, 탭 및 개행 문자를 구분 기호로 사용하게 되는데, 이는 분명히 공백이 있는 문자열에서는 작동하지 않습니다. 빈 문자열로 설정 하면 IFS해당 구분 기호가 없으므로 항상 하나의 필드만 얻게 됩니다.

그러나 예를 들어 줄 바꿈으로만 설정할 수 있습니다 IFS(문자열이 여러 줄이 아니라고 가정).

#!/bin/bash
IFS=$'\n'
foo() {
    printf "%s\n" "$@"
}

nargs() {
    echo "number of arguments nargs got: $#"
} 

nargs $(foo firstarg "multi word string" "also a multi word string")

(그러나 명령 대체는 에 관계없이 후행 개행 문자를 제거하므로 목록 끝에 빈 문자열을 사용할 수 없습니다. IFS)

또 다른 접근 방식은 함수의 표준 출력을 사용하는 것이 아니라 변수 이름을 함수에 전달하고 함수가 nameref를 통해 명명된 배열에 쓰도록 하는 것입니다.

#!/bin/bash
bar() {
    declare -n _out="$1"
    shift
    _out=("$@")
}

nargs() {
    echo "number of arguments nargs got: $#"
} 

bar tmparr firstarg "multi word string" "also a multi word string"
nargs "${tmparr[@]}"

_out(호출된 변수가 함수 외부에도 존재 하는 경우 변수 범위 지정에 문제가 있습니다 .)

또한 따옴표가 없는 확장(변수 또는 명령 대체)이 있는 경우 그 결과는 파일 이름 와일드카드의 영향을 받기 때문에 12 * 34비활성화 와일드카드도 사용하지 않는 한 이와 같은 출력은 심각하게 왜곡될 것입니다 set -f.

답변2

원래 원했던 건매개변수 확장 후 단어 분할 비활성화, 그러니까 쓰지 마세요

mcd() {
  mkdir -p "$1"
  cd "$1"
}

당신은 쓸 수 있습니다

mcd() {
  mkdir -p $1
  cd $1
}

그것은 무슨 일이 있어도 작동합니다 mcd "foo bar".

이는 대부분의 사용 사례에서 선호되는 동작이므로 zsh기본 동작으로 설정됩니다( SH_SPLIT_WORD옵션을 사용하여 전역적으로 비활성화하거나 를 작성하여 개별적으로 비활성화 할 수 있음 ${=1}).

해결방안을 요구하신 건 알지만 bash"zsh대신 사용bash"이것은 내 문제 중 많은 부분에 대한 답이었고 zsh어느 ​​날 문자 그대로 이 방법으로 전환했다가 벗어나게 되었습니다. 그래서 이 조언을 다른 사람들에게 전달하게 되어 기쁩니다. IMHO, 이를 고수할 이유가 거의 없습니다 bash.

관련 정보