tar 배열 변수를 전달할 때 "계산할 수 없음: 디렉터리에 해당 파일이 없습니다."

tar 배열 변수를 전달할 때 "계산할 수 없음: 디렉터리에 해당 파일이 없습니다."

디렉터리에 파일의 아카이브(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여러번 호출될 수 있기 때문입니다. 과거에 새로운 아카이브를 생성하면 호출될 때마다 잘립니다(수천 개의 파일이 발견되면 여러 번 발생할 수 있음). 대신, 우리는 계속해서 아카이브를 업데이트하고 있습니다.findtartar -ctarfindtar -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 -

를 사용하면 -print0GNU가 옵션을 사용하여 읽을 수 있는 findnul로 구분된 경로 이름이 출력됩니다.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

zshGNU와 함께 사용 하거나 다음을 수행 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 한정자: 숨겨진 파일을 포함하고 일반 파일만 선택합니다.

관련 정보