bash에서 하나의 변수로만 구성된 인수 목록

bash에서 하나의 변수로만 구성된 인수 목록

다음과 같은 파일(와일드카드 또는 폴더가 있는 파일) 목록을 포함하는 입력 매개변수가 있습니다.

list="file1 dir1 **.data **.source"

이제 이 목록의 각 요소에는 접두사가 붙어야 하며 다음과 같이 --filter=+명령 인수 목록으로 바뀌어야 합니다 rsync.

args='--filter=="+ file1" --filter="+ dir1" --filter="+ **.data" --filter="+ **.source"'

그래서 지나갈 때$매개변수각 인수를 올바르게 수신 해야 합니다 rsync $args. 여기서 "+" 안의 공백은 두 인수의 구분 기호가 아닌 인수의 한 문자여야 합니다.

내장된 쉘 명령만 사용하여 쉘 스크립트(bash)에서 이 작업을 어떻게 수행할 수 있습니까? 명령 은 rsync각 매개변수를 올바르게 수신해야 합니다.

실패한 시도:

#!/bin/bash
set -f
list="file1 dir1 **.data **.source"
ct=0
arr=""
for i in $list; do
    ct=$(( ct + 1 ))
    arr[$ct]="--filter='+ $i'"
done
args=${arr[*]}

set -x
echo args:$args
rsync $args srcdir destdir
set +x

실행되면(폴더가 srcdir현재 디렉터리에 존재한다고 가정) 다음이 표시됩니다.

$ ./test
+ echo args: '--filter='\''+' 'file1'\''' '--filter='\''+' 'dir1'\''' '--filter='\''+' '**.data'\''' '--filter='\''+' '**.source'\'''
args: --filter='+ file1' --filter='+ dir1' --filter='+ **.data' --filter='+ **.source'
+ rsync '--filter='\''+' 'file1'\''' '--filter='\''+' 'dir1'\''' '--filter='\''+' '**.data'\''' '--filter='\''+' '**.source'\''' a b
Unknown filter rule: `'+'
rsync error: syntax or usage error (code 1) at exclude.c(904) [client=3.1.1]
+ set +x

echo각 매개변수가 올바르게 표시되는지 확인하세요 .

args: --filter='+ file1' --filter='+ dir1' --filter='+ **.data' --filter='+ **.source'

rsync"+"가 인수를 완성하고 공백이 인수의 일부가 아니라 구분 기호이므로 모든 인수가 삭제되므로 명령이 각 인수를 올바르게 이해하는 것처럼 보이지 않습니다 .

답변1

파일 이름 및 패턴 목록을 단일 문자열로 사용하는 대신 이를 배열로 시작할 수 있습니다.

list=(file1 dir1 "**.data" "**.source")

그런 다음 요소를 반복합니다.

args=()
for item in "${list[@]}" ; do
    args+=(--filter="+ $item")
done

--filter=+ file1이렇게 하면 매개변수 문자열 안에 따옴표 없이 유사한 매개변수가 생성됩니다 . (따옴표가 들어가는 것을 원하지 않습니다 rsync. 예를 들어 인용문을 포함하는 필터 규칙에 대해 불평합니다 rsync "--filter='+ foo'" ....)

명령에 배열을 전달할 때 다음을 "${args[@]}"사용하여 배열 요소를 고유한 문자열로 전달해야 합니다.

rsync "${args[@]}" "$srcdir" "$destdir"

대신 "--filter=+ foo"을 사용할 수 있을 것 같습니다 --include=foo. 이렇게 하면 매개변수에서 문제가 있는 공백이 제거됩니다(그러나 파일 이름 패턴에서 공백이나 와일드카드는 제거되지 않습니다).


귀하의 경우에는 set -f와일드카드를 비활성화했고 for i in $list작동할 것입니다. 그러나 배열이 필요하기 때문에 처음에는 배열을 사용하는 것이 더 나을 것입니다.

더 중요한 것은 할당이 args=${arr[*]}배열을 단일 문자열로 평면화한다는 것입니다. 이제 인수 내의 공백과 인수 사이의 공백은 동일하며 --filter=+ file1 --filter=+ dir1 ...쉘은 서로 다른 유형의 공백을 구별할 수 없습니다. 따옴표가 없는 확장은 $args모든 공백으로 분할됩니다( set -x지저분한 따옴표를 구문 분석하려는 경우 출력에 이 내용이 표시됩니다.)

실제로 이 할당에서는 배열 사용의 모든 이점이 의미가 없게 됩니다.

관련 정보