나는 내가 하고 싶은 모든 것을 웹에서 찾았지만 내 사용 사례에 정확히 맞는 것은 하나도 없었습니다.
여러 개의 특정 파일과 특정 파일 확장자를 가진 파일을 데스크탑의 디렉터리에 복사하는 스크립트를 작성하려고 합니다. 또한 bash 3.2에서도 실행되어야 합니다.
이 줄은 나를 넘어지게 만드는 줄입니다. 패턴 일치, 순서, 확장 및 와일드카드와 관련이 있을 수 있다는 것을 알고 있습니다.
#!/usr/bin/env bash
declare -a backup_files=(*.{id,nsf}, "desktop8.ndk", "archive", "user.dic");
declare -a notes_data_directory=~/Library/Application\ Support/IBM\ Notes\ Data/;
declare -a notes_backup_directory=~/Desktop/Notes\ Backup;
mkdir "$notes_backup_directory";
cd "$notes_data_directory";
for i in "${backup_files[@]}"
do
cp -nipvR "$notes_data_directory$i" "$notes_backup_directory";
# Also tried this
# find "$notes_data_directory""$i" -exec cp -nipvR {} "$notes_backup_directory" \;
done
cd -
내가 이렇게 하면 echo "$backup_files"
다음과 같은 결과를 얻을 수 있습니다.
*.{id,nsf}, desktop8.ndk, user.dic
나는 그것이 구문과 관련이 있다고 확신합니다. 나는 단지 어디에 있는지 모른다.
답변1
특정 텍스트 주위에 따옴표를 넣으면 와일드카드 확장 및 중괄호 확장과 같은 확장이 비활성화됩니다. 이를 기억하는 논리적인 방법은 단어 목록을 생성하지만 인용문과 같은 문맥을 통해 내용이 단일 단어임을 보장한다는 것입니다.
또한 가짜 쉼표가 있습니다. 쉘 스크립트에서 단어는 공백으로 구분됩니다.
declare -a backup_files=(*.{id,nsf} "desktop8.ndk" "user.dic")
다음과 같이 쓸 수 있습니다.
backup_files=(*.{id,nsf} "desktop8.ndk" "user.dic")
backup_files
함수에서 지역 변수로 선언하지 않는 한 .
패턴 중 하나가 파일과 일치하지 않으면 확장되지 않은 상태로 유지됩니다. 예를 들어, 빈 디렉토리에서는 , 및 4개의 요소로 끝납니다 *.id
. 이것을 에 전달하고 싶다면 괜찮습니다. 보다 일반적으로 처리하는 동안 각 요소가 기존 파일인지 확인하여 이 문제를 해결할 수 있습니다.*.nsf
desktop8.ndk
user.dic
rm -f
for x in "${backup_files[@]}"; do
if [[ ! -e "$x" ]]; then continue; fi
…
done
(여담으로, 배열의 요소에 접근하는 것은 인용된 문자열이 단어 목록이 아닌 단어를 생성한다는 규칙의 예외라는 점에 유의하십시오. 배열 확장을 사용하면 큰따옴표가 다음을 보장합니다.각 요소패턴 일치 및 단어 분할을 수행하는 대신 개별 단어로 종료됩니다. "$@"
와 같은 변형을 포함한 유일한 예외입니다 . )
또는 nullglob
일치하는 파일이 없는 경우 패턴 일치가 빈 목록을 생성하도록 옵션을 설정할 수 있습니다.
shopt -s nullglob
backup_files=(*.{id,nsf} "desktop8.ndk" "archive" "user.dic")
그러면 배열에는 기존 .id
합계 .nsf
파일만 포함되지만 어쨌든 합계가 포함됩니다 desktop8.ndk
. user.dic
이러한 파일이 존재하지 않는 경우 패턴으로 설정하여 제외할 수도 있습니다.
shopt -s nullglob
backup_files=(*.{id,nsf} desktop8.nd[k] archiv[e] user.di[c])
배열을 정의할 때 중괄호와 와일드카드가 확장됩니다. 따라서 패턴은 현재 디렉터리의 파일과 일치합니다. 스크립트가 의도하지 않은 이상한 일을 하고 있습니다. 현재 디렉터리에서 파일 이름을 수집하고 다른 디렉터리에서 같은 이름의 파일을 복사하고 있습니다 $notes_data_directory
. 다른 디렉터리에 있는 파일을 일치시키려면 다음과 같이 말해야 합니다.
notes_data_directory=~/Library/Application\ Support/IBM\ Notes\ Data/
notes_backup_directory=~/Desktop/Notes\ Backup
backup_files=("$notes_data_directory/"*.{id,nsf} "$notes_data_directory/desktop8.ndk" "$notes_data_directory/archive" "$notes_data_directory/user.dic")
for i in "${backup_files[@]}"
do
cp -nipvR "$i" "$notes_backup_directory"
done
중괄호 확장을 사용하여 정의를 단축할 수 있습니다 backup_files
.
backup_files=("$notes_data_directory/"{*.{id,nsf},desktop8.ndk,archive,user.dic})
또는 복사하기 전에 디렉토리로 변경하십시오.
notes_data_directory=~/Library/Application\ Support/IBM\ Notes\ Data/
notes_backup_directory=~/Desktop/Notes\ Backup
cd "$notes_data_directory"
shopt -s nullglob
backup_files=(*.{id,nsf} desktop8.nd[k] archiv[e] user.di[c])
for i in "${backup_files[@]}"
do
cp -nipvR "$i" "$notes_backup_directory"
done
또 다른 접근 방식은 패턴 목록을 배열에 저장하고 따옴표가 없는 변수를 사용하여 패턴을 확장하는 것입니다. 소스 줄을 구문 분석할 때 중괄호 확장이 발생해야 하며 와일드카드는 확장되지 않은 상태로 배열에 저장되어야 합니다. 패턴에 공백이 있으면 따옴표로 묶어야 합니다. 이렇게 하는 것은 약간 까다롭습니다. 나는 이 접근 방식을 권장하지 않습니다. 따르기가 어렵습니다. 패턴은 결국 파일과 일치할 수도 있고 일치하지 않을 수도 있지만 cp
최소한 하나의 소스 파일이 필요하므로 패턴이 파일과 일치하지 않는 경우를 별도로 처리해야 합니다.
notes_data_directory=~/Library/Application\ Support/IBM\ Notes\ Data/
notes_backup_directory=~/Desktop/Notes\ Backup
backup_patterns=(\*.{id,nsf} "desktop8.nd[k]" "archiv[e]" "user.di[c]")
# equivalent to backup_patterns=("*.id" "*.nsf" "desktop8.nd[k]" "archiv[e]" "user.di[c]")
shopt -s nullglob
for i in "${backup_patterns[@]}"
do
files=("$notes_data_directory/"$i)
if [[ ${#files[@]} -ne 0 ]]; then
cp -nipvR "${files[@]}" "$notes_backup_directory"
fi
done