디렉터리에 파일의 아카이브(tar)를 생성하는 bash 스크립트를 작성하려고 합니다. 이와 같은 bash 스크립트(./backup.bash pdf txt bak)를 호출할 때 파일 확장자를 매개변수로 전달해야 합니다. 저는 이러한 매개변수를 저장하기 위해 배열을 사용하고 있습니다. (ls | grep -i {array})는 입력 배열의 파일 확장자와 일치하는 디렉터리의 모든 파일을 찾고 발견된 파일을 나열합니다. (find . -type) 이러한 확장자는 해당 확장자와 연결된 파일을 찾는 데 사용됩니다. (tar cvf)는 작업 디렉터리에 backup.tar라는 백업 파일을 생성합니다. tar 명령 끝에 배열을 나열했지만 이제 생각해보면 find 명령을 tar 명령에 파이프할 수 있을 것 같습니다.
my_array=([$@])
ls | grep -i \{my_array[$@]}
find . -type f \( -name "my_array[$@]" \)
tar cvf ./PATH/backup.tar my_array[$@]
답변1
이 문제를 해결하는 데에는 두 가지 주요 문제가 있습니다. 사용자가 지정한 특정 파일 이름 접미사가 있는 모든 파일을 찾아서 아카이브에 추가해야 합니다 tar
.
이 find
명령에는 -name
사용하려는 옵션이 있지만 단일 파일 이름 패턴만 사용합니다. 스크립트 사용자가 여러 파일 이름 접미사를 제공하므로 -name
접미사 수만큼 많은 옵션을 사용해야 합니다.
즉, -name "PATTERN"
여러 옵션의 배열을 구성해야 하며 -o
각 옵션 사이에 중간 값이 있어야 합니다(그들 사이의 논리적 "OR"을 나타냄). 그런 다음 find
지정된 파일 이름 접미사가 있는 파일 이름을 검색 하는 데 사용됩니다 .
이는 배열을 수정하여 수행됩니다 $@
.
#!/bin/sh
for suffix do
shift
set -- "$@" -o -name "*.$suffix"
done
shift # remove the very first "-o" from $@
find . -type f \( "$@" \)
이는 $@
명령줄에 지정된 접미사가 처음부터 이미 포함되어 있는 배열을 수정합니다. 루프에서 이전 요소를 제거 $@
하고 배열 끝에 단어를 삽입합니다.
이 스크립트가 호출되면
sh script.sh sh txt c
find
다음과 동일한 명령을 구성합니다 .
find . -type f \( -name '*.sh' -o -name '*.txt' -o -name '*.c' \)
그러면 관련 파일이 모두 검색됩니다. 이제 아카이브에 추가하기만 하면 됩니다.
GNU tar
(예: BSD는 아님 tar
)의 경우 이 r
작업을 통해업데이트 또는 생성아카이브(BSD는 tar
업데이트만 하고 새 아카이브를 생성하지는 않습니다).
backup=./PATH/backup.tar
rm -f "$backup"
find . -type f \( "$@" \) -exec tar -r -v -f "$backup" {} +
./PATH/backup.tar
그러면 관련 파일이 포함된 아카이브가 생성됩니다.
제가 사용하지 않는 이유 tar -c
는 이렇게 호출하면 tar
여러번 호출될 수 있기 때문입니다. 과거에 새로운 아카이브를 생성하면 호출될 때마다 잘립니다(수천 개의 파일이 발견되면 여러 번 발생할 수 있음). 대신, 우리는 계속해서 아카이브를 업데이트하고 있습니다.find
tar
tar -c
tar
find
tar -r
따라서 전체 스크립트는 다음과 같습니다.
#!/bin/sh
backup=./PATH/backup.tar
if [ "$#" -eq 0 ]; then
echo 'No filename suffixes given' >&2
exit 1
fi
for suffix do
shift
set -- "$@" -o -name "*.$suffix"
done
shift # remove the very first "-o" from $@
rm -f "$backup"
find . -type f \( "$@" \) -exec tar -r -v -f "$backup" {} +
위 스크립트에서 따옴표를 사용한 것은 의도적인 것입니다. 공백, 개행 및 기타 특이한 문자가 포함된 이름을 포함하여 허용된 파일 이름을 사용하여 파일을 보관할 수 있습니다.
관련된:
find
가 포함된 구현을 사용하는 경우 다음 스크립트에 표시된 대로 -print0
찾은 경로 이름을 GNU에 전달할 수도 있습니다 .tar
#!/bin/sh
backup=./PATH/backup.tar
if [ "$#" -eq 0 ]; then
echo 'No filename suffixes given' >&2
exit 1
fi
for suffix do
shift
set -- "$@" -o -name "*.$suffix"
done
shift # remove the very first "-o" from $@
find . -type f \( "$@" \) -print0 | tar -c -v -f "$backup" --null -T -
를 사용하면 -print0
GNU가 옵션을 사용하여 읽을 수 있는 find
nul로 구분된 경로 이름이 출력됩니다.tar
--null -T -
bash
특정 스크립트 로서의 마지막 스크립트 (배열을 옵션 names
으로 사용 -name
):
#!/bin/bash
backup=./PATH/backup.tar
if [ "$#" -eq 0 ]; then
echo 'No filename suffixes given' >&2
exit 1
fi
names=( -name "*.$1" )
shift
for suffix do
names+=( -o -name "*.$suffix" )
done
find . -type f \( "${names[@]}" \) -print0 | tar -c -v -f "$backup" --null -T -
답변2
zsh
GNU와 함께 사용 하거나 다음을 수행 tar
하십시오 bsdtar
.
#! /bin/zsh -
set -o extendedglob
output=file.tar.gz
printf '%s\0' **/*.(${(j:|:)~${(b)@}})~$output(D.) |
tar --null -cf - -T - | xz > $output
${(b)@}
: 패턴으로 취급되지 않도록 위치 매개변수를 인용합니다.${(j:|:)...}
: 결과 단어를 다음과 연결합니다.|
${~var}
: 확장을 와일드카드 패턴으로 처리합니다(이제jpg|gif|\*
위치 매개변수가jpg
,gif
, 인 것처럼 보입니다*
).**/
: 모든 수준의 하위 디렉터리pattern~$output
:glob 확장자에서 출력 파일 자체를 제외합니다.(D.)
:glob 한정자: 숨겨진 파일을 포함하고 일반 파일만 선택합니다.