필요할 때 백슬래시가 포함된 파일 목록을 변수에 어떻게 저장할 수 있나요?

필요할 때 백슬래시가 포함된 파일 목록을 변수에 어떻게 저장할 수 있나요?

주요 문제:

백업을 수행하는 스크립트를 작성 중입니다. 다음을 통해 파일 목록을 만듭니다.

LISTOFFILES=$(find ~ \( -name '*.[pP][dD][fF]' -o -name '*.[oO][dD][tT]' \))

이 변수는 LISTOFFILES대략 다음을 저장합니다.

/home/user/file1.pdf /home/user/file2.odt /home/user/Python Tutorial.pdf

다음 단계는 다음과 같습니다.

tar cvf backup.tar $LISTOFFILES

Bash 응답은 다음과 같습니다.

/home/user/file1.pdf
/home/user/file2.odt
/home/user/Python: Cannot stat: No such file or directory
tar: Tutorial.pdf

나는 Bash가 가정 Python하고 Tutorial.pdf다른 파일이라는 것을 알고 있습니다.

백슬래시가 포함된 파일 목록을 만드는 방법이 있습니까 ? 아니면 파이프와 함께 사용 find하도록 변경해야 합니까 ?ls

나는 당신의 조언과 조언을 읽고 싶습니다.

내 다른 질문:

이 질문에 대한 답변은 중요하지 않지만 팁이 도움이 될 수 있습니다.

파일 경로가 아닌 파일 이름만 포함된 파일을 나열하려면 어떻게 해야 합니까?

예 : file./home/user/file

find성공하지 못한 채 명령 prune과 옵션을 사용해 보았습니다 path.

답변1

주요 문제에 대해서는 다른 접근 방식을 취해야 합니다. 귀하의 접근 방식은 모든 파일을 $LISTOFFILES의 단일 문자열에 넣는 것입니다. 그런 다음 액세스할 때 따옴표를 사용하지 않으므로 공백으로 구분되어 표시되는 결과를 제공합니다.

원하는 결과를 얻는 가장 간단한 방법은 다음과 같습니다.

find ~ \( -name '*.[pP][dD][fF]' -o -name '*.[oO][dD][tT]' \) -print0 | xargs -0 tar cvf backup.tar

우리가 하는 일은 find를 실행하고 각 결과를 NULL 문자(-print0 부분)로 분리하는 것뿐입니다. 그런 다음 find의 출력은 xargs로 파이프되어 NULL 문자로 구분된 파일 목록을 읽고(-0 매개변수는 xargs에게 이를 수행하도록 지시함) 파일 목록을 "tar"에 인수로 전달합니다.

find두 번째 질문: 명령에서 파일 이름을 얻으 려면 printf를 사용하십시오.

find /path/to -printf '%f\n'
file.txt

단순히 find가 아닌 일반적인 의미라면 basename.

# basename /path/to/file.txt
file.txt

basename은 정확히 그 일만 수행하도록 설계되었으며 다른 작업은 수행하지 않습니다.

답변2

시도가 실패한 이유와 해결 방법

반환된 파일 이름 목록을 누적할 수 있지만 find파일 이름에 줄 바꿈이 없고 예방 조치를 취하는 경우에만 가능합니다.

$LISTOFFILES아래와 같이 따옴표 없이 명령 대체 또는 변수 확장을 작성하면 쉘이 다음을 실행합니다.분사그리고와일드카드(와일드카드 확장)결과에 대해.

규칙: 명령 대체 및 변수 확장은 항상 큰따옴표로 묶으십시오.
예외: 큰따옴표를 생략해야 하는 이유와 그렇게 해도 안전한 이유를 이해하는 경우.

여기서는 토큰화가 문자열을 개행으로 구분된 비트로 분할하므로 큰따옴표를 제거해야 합니다. 그러나 기본적으로 다른 공백 문자로도 분할됩니다. 따라서 안전을 확보하고 와일드카드를 꺼야 합니다. 설정을 통해 전자를 수행할 수 있습니다.IFS바꾸다단일 줄 바꿈 문자로 변환하고 후자는 호출하여set -f.

IFS='
'
set -f
tar cvf backup.tar $LISTOFFILES

백슬래시가 포함되어 있지 않습니다. 에서 파일 이름을 입력할 때가 아니라 파일 이름을 직접 입력할 때 백슬래시를 사용하십시오 find.

일반적인 사용 방법find

출력을 구문 분석해서는 안 되며 find, 파일에서 실행하려는 명령을 호출하는 작업을 전달해야 합니다 -exec. 이는 파일이 너무 많아 최대 명령줄 길이를 초과하는 상황을 해결합니다. 프로그램은 필요한 만큼 호출됩니다.

여기서는 여러 번 호출할 수 없기 때문에 조금 더 어렵습니다 tar -c(호출할 때마다 새로운 빈 아카이브로 시작하게 됩니다). 하지만 보세요Tar는 디렉토리 구조를 유지하면서 디렉토리의 모든 PDF를 압축합니다.

더 간단한 방법

파일이 많지 않고 ksh93, bash ≥4 또는 zsh를 실행 중인 경우 **와일드카드를 사용하여 하위 디렉터리로 재귀적으로 이동하세요. 먼저 몇 가지 셸 옵션을 설정해야 합니다.

set -o globstar                  # on ksh93
shopt -s globstar -s extglob     # on bash 4
setopt ksh_glob                  # on zsh
tar cvf backup.tar ~/**/*.@(PDF|pdf|ODT|odt)

zsh에서는 특별한 설정 없이 패턴 을 ~/**/*.(PDF|pdf|ODT|odt).setopt extglob~/**/(#i)*.(pdf|odt)

아니면 당신은 사용할 수 있습니다공원:

pax -w -x ustar -s '/\.pdf$/&/' -s '/\.PDF$/&/' -s '/\.odt$/&/' -s '/\.ODT$/&/' -s '/.*//' ~ >backup.tar

경로 접두사가 필요하지 않은 경우

tar및 를 사용하는 방법에는 여러 가지가 있지만 pax가장 쉬운 방법은 먼저 보관하려는 디렉터리로 변경하는 것입니다.

( IFS='
'; set -f; cd ~ && tar cvf /path/to/backup.tar $(find . …) )
( cd ~ && pax -w … . ) >backup.tar

답변3

첫 번째 질문:

첫 번째 질문에 대한 답변은 다음과 같습니다.quotes.

하는 대신 ->tar cvf backup.tar $LISTOFFILES

이렇게 하세요 ->tar cvf backup.tar "$LISTOFFILES"

예를 살펴보겠습니다. (파일이 내 컴퓨터에 존재하지 않더라도 이 데모를 위해 파일 중 하나를 가져왔습니다. 받은 오류는 따옴표 포함 및 제외)를 참조하세요.

[jaypal:~] file="/home/user/Python Tutorial.pdf"

[jaypal:~] ls $file
ls: /home/user/Python: No such file or directory
ls: Tutorial.pdf: No such file or directory

파일이 2개 /home/user/Python있는데 오류가 발생했습니다 Tutorial.pdf. 우리가 무엇을 얻는 quote지 봅시다 variable.

[jaypal:~] ls "$file"
ls: /home/user/Python Tutorial.pdf: No such file or directory

파일에 오류가 하나만 있습니다./home/user/Python Tutorial.pdf

두 번째 질문:

가지치기에는 /path/to/file여러 가지 방법이 있습니다 . 제가 가장 좋아하는 것은 인데, awk하나도 보여드리겠습니다 sed.

sed방법:

[jaypal:~/Temp] echo "$filename"
/home/user/file1.pdf /home/user/file2.odt /home/user/Python Tutorial.pdf

[jaypal:~/Temp] echo "$filename" | sed 's@/home/user/@@g'
file1.pdf file2.odt Python Tutorial.pdf

다음과 같이 스크립트에 포함시킬 수 있습니다.

LISTOFFILES=$(find ~ \( -name '*.[pP][dD][fF]' -o -name '*.[oO][dD][tT]' \) | sed 's@/home/user/@@g' )

여기서 기억해야 할 점은 우리가 하고 있는 일입니다 substitution. 여러 디렉터리의 파일을 처리 하는 경우 많은 교체 작업을 수행하거나(아예!) 다음을 수행할 /home/user/수 있습니다 .nothingfindawk

awk방법:

awk -F"/" '{print $NF}'

그래 그거야. find모든 디렉터리 또는 해당 하위 디렉터리의 파일 에 적용됩니다 .

따라서 스크립트는 다음과 같은 방법으로 구현할 수 있습니다.

LISTOFFILES=$(find ~ \( -name '*.[pP][dD][fF]' -o -name '*.[oO][dD][tT]' \) | awk -F"/" '{print $NF}')

기타 팁과 요령:

다음은 귀하에게 유용할 것으로 생각되는 몇 가지 무작위 팁입니다.

find파일 이름은 현재 가지고 있는 이름을 insensitively사용하세요 . iname이것 좀 보세요 -

[jaypal:~/Temp] find . -name "j*.txt"
./jP.txt

[jaypal:~/Temp] find . -iname "j*.txt"
./jj.TXT
./jP.txt

정리 /path/to/file하는 다른 방법 basename은 .

[jaypal:~/Temp] filename="/usr/bin/java.pdf"

[jaypal:~/Temp] echo "$filename"
/usr/bin/java.pdf

[jaypal:~/Temp] basename "$filename"
java.pdf

도움이 되었기를 바랍니다!

관련 정보