Bash: bash 함수에 중괄호를 인수로 전달합니다.

Bash: bash 함수에 중괄호를 인수로 전달합니다.

나는 다음 패턴을 사용하여 파일을 검색하는 것을 좋아합니다.

grep --color=auto -iRnHr --include={*.js,*.html,} --exclude-dir={release,dev,} "span" .

그러나 다음과 같이 bash 명령에 이를 포함하고 싶습니다.

findinfiles {*.js,*.html,} {release,dev,} "span"  // syntax is just a guessing

$1$2이러한 유형의 중괄호를 bash 함수에 전달하고 , 등과 함께 사용하는 방법을 알 수 없습니다 . 다음을 사용할 때 :

function findinfiles() {
    echo $1, $2, $3
}

그 다음에:

me@pc ~> findinfiles {*.js,*.html,} {release,dev,} "span"
*.js, *.html, release

물론 grep에 인수를 전달하는 것은 이런 방식으로 작동하지 않습니다. 매개변수가 색인화되었지만 올바르게 그룹화되지 않은 것 같습니다.

이런 유형의 논쟁을 처리하는 방법을 가르쳐 줄 수 있는 사람이 있습니까?

답변1

이것을 실행하면 findinfiles {*.js,*.html,} {release,dev,} "span"다음과 같은 일이 발생합니다.

  1. Bash는 따옴표를 구문 분석하고 명령을 단어로 나눕니다: findinfiles, {*.js,*.html,} {release,dev,} span.
  2. Bash는 중괄호를 확장하여 , , , findinfiles, *.js, 단어 목록 을 생성합니다 .*.htmlreleasedevspan
  3. Bash는 와일드카드 패턴을 일치하는 파일 이름 목록 *.js으로 확장합니다. *.html두 패턴 중 어느 것과도 일치하는 파일 이름이 없으면 그대로 유지됩니다.
  4. Bash는 name 을 조회하고 findinfiles그것이 함수임을 확인한 다음 제공된 인수를 사용하여 함수를 실행합니다.

함수 호출 시 중괄호와 와일드카드의 확장을 방지할 수 있지만 중괄호는 인수에 문자 그대로 표시되므로 특히 유용하지 않습니다.

함수 호출 형식을 변경하는 것이 좋습니다. 중괄호를 사용하지 말고 쉼표만 사용하고 함수 내에서 인수를 쉼표로 수동으로 구분하세요.

findinfiles () {
  local patterns="$1" excludes="$2" pattern="$3"
  shift 3
  typeset -a cmd dirs
  if [[ $# -eq 0 ]]; then dirs=(.); else dirs=("$@"); fi
  cmd=(grep --color=auto -iRnHr)
  local IFS=,
  for x in $patterns; do
    cmd+=("--include=$x")
  done
  for x in $excludes; do
    cmd+=("--exclude-dir=$x")
  done
  "${cmd[@]}" "${dirs}"
}

설명하다:

  • 처음 세 개의 매개변수를 지역 변수에 저장합니다. 추가 인수는 검색할 디렉터리입니다.
  • dirs추가 매개변수 목록으로 설정합니다 . 그렇지 않은 경우 .(현재 디렉터리)가 사용됩니다.
  • 쉼표로 설정합니다 IFS. 스크립트 $patterns에 위와 같이 인용되지 않은 변수 확장이 포함된 경우 $excludes쉘은 다음을 수행합니다.

    1. 변수를 해당 값으로 바꿉니다.
    2. 에 있는 문자가 포함될 때마다 변수를 별도의 단어로 분할합니다 IFS. 기본적으로 IFS공백 문자(공백, 탭 및 줄 바꿈)가 포함됩니다.
    3. 각 단어를 와일드카드 패턴으로 처리하고 일치하는 파일 목록으로 확장합니다. 일치하는 파일이 없으면 패턴이 유지됩니다.

    (이러한 확장 단계를 피하려면 patterns="$1"위 스크립트에서와 같이 변수 대체에 큰따옴표를 사용하십시오.)

  • 이 함수는 배열 변수에서 증분적으로 실행되도록 명령줄을 작성합니다 cmd. 마지막으로 명령이 실행됩니다.

또는 다음 설정을 기반으로 빌드할 수 있습니다.

shopt -s extglob globstar
fif_excludes='release dev'
alias fif='grep --color=auto -inH $fif_excludes'

다음 명령을 실행하십시오.

fif span **/*.@(js|html)

설명하다:

  • shopt -s extglob또는 @(js|html)일치하는 와일드카드 패턴 형식을 활성화합니다 . (이 옵션은 다른 모드 형식을 활성화합니다. 자세한 내용은 설명서를 참조하세요.)jshtml
  • shopt -s globstar모든 깊이의 하위 디렉터리와 일치하는 패턴을 활성화합니다 **/(예: 재귀 순회 수행).
  • 제외 목록(자주 발생하지는 않을 것으로 예상됨)을 변경하려면 fif_excludes변수를 수정하십시오.

답변2

bash는 .. {a,b,}1로 확장됩니다 a1 b1 1.

귀하의 명령은 다음으로 확장됩니다 grep --color=auto -iRnHr --include=*.js --include=*.html --include= --exclude-dir=release --exclude-dir=dev --exclude-dir= span(js 및 html 파일이 없는 디렉터리, 그렇지 않으면 모든 파일이 포함됩니다).

매개변수를 인용할 수 있지만 이는 이상적이지 않을 수 있습니다... findinfiles "{*.js,*.html,}" "{release,dev,}" "span"(그러면 여전히 와일드카드가 필요합니다)

eval그러면 다음 버전과 같이 를 사용하여 올바르게 확장할 수 있습니다 .

function findinfiles() {
    eval "grep --color=auto -iRnHr --include=$1 --exclude-dir=$2 '$3'"
}

관련 정보