특수한 경우 파일 삭제, 가능하면 재귀적으로 삭제

특수한 경우 파일 삭제, 가능하면 재귀적으로 삭제

저는 상당히 복잡한 조건부 삭제 작업을 수행할 수 있는 유닉스 명령 시퀀스를 찾고 있습니다.

파일에 "[NAME].rec" 또는 "[NAME].mpg"라는 이름의 해당 파일이 없으면 확장자가 "[NAME].cut" 및 "[NAME].cut.bak"인 모든 파일이 삭제됩니다. 같은 폴더.

이 명령은 최소한의 커널이 있는 통합 장치에서 실행되어야 하므로 "특수 도구"가 사용되지 않습니다. 예를 들어 "ls" 및 "rm"을 사용할 수 있지만 "find"는 존재하지 않습니다(즉, 의존하고 싶지 않은 외부 도구를 통해서만 가능).

가능하다면 이 명령은 하위 디렉터리에서도 반복적으로 삭제해야 합니다.

배경은 다음과 같습니다. 저는 녹화된 쇼를 잘라낼 수 있는 Linux 기반 PVR용 도구를 개발 중입니다. 각 녹화(확장자 .rec 또는 .mpg)에 대해 클립 마커가 .cut 파일에 저장됩니다. 일부 녹음이 이동/이름 변경/삭제되면 해당 잘라낸 파일은 디스크에서 쓸모 없게 됩니다. 쓸모없는 컷 파일을 삭제하기 위해 C로 구현했습니다. 그런데 (간단한) 시스템 기반 솔루션이 있는지 궁금합니다. 이 경우 "시스템"을 통해 백그라운드에서 실행될 수 있으므로 내 앱의 반응성이 향상됩니다.

다음은 PVR 펌웨어에 포함된 명령입니다.

선호도, arp, awk, 기본 이름, bash, busybox, 고양이, chgrp, chmod, chown, cmp, cp, crushfsck, 컷, 날짜, dd, df, dirname, dmesg, du, echo, egrep, env, expr, false, fgrep, flash_erase, flash_eraseall, flash_info, 무료, getty, grep, 헤더, hexdump, 호스트 이름, id, ifconfig, 설치, kill, killall, ln, logger, 로그인, ls, md5sum, mkcramfs, mkdir, mknod, mktemp, 더보기, 설치, mv, nice, norcleanmark, od, passwd, pidof, ping, pmtest, portmap, printenv, printf, ps, pwd, readlink, renice, rm, rmdir, 라우팅, sed, seq, sh, 종료, 절전, 정렬, string, stty, sync, tail, tee, telnet, tftp, time,tinylogin, touch, tr, true, tty, Twin, umount, uname, uniq, usleep, vi, wc, which, whoami, xargs, yes

나에게 줄 조언이 있나요?

답변1

더 간단하게 만들 수는 없지만 작동합니다.이름에 개행 문자가 포함된 파일이 대상 디렉토리에 존재하지 않는다고 가정합니다.; 먼저 다음을 사용하여 명령을 테스트합니다.

find . -type f \( -name "*.cut" -o -name "*.cut.bak" \) -exec bash -c '[ -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").rec" -o -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").mpg" ] && echo "{}"' \;

나열된 파일이 삭제될 것으로 예상되는 파일인 경우 다음 명령을 실행하여 계속 진행할 수 있습니다.

find . -type f \( -name "*.cut" -o -name "*.cut.bak" \) -exec bash -c '[ -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").rec" -o -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").mpg" ] && rm "{}"' \;

임시로 생성된 디렉터리 계층 구조를 테스트합니다.

~/tmp$ tree
.
└── dir1
    ├── file1.cut
    ├── file1.cut.bak
    ├── file1.rec
    ├── file2.cut
    ├── file2.cut.bak
    ├── file2.mpg
    ├── file3.cut
    ├── file3.cut.bak
    └── subdir1
        ├── file1.cut
        ├── file1.cut.bak
        ├── file1.rec
        ├── file2.cut
        ├── file2.cut.bak
        ├── file2.mpg
        ├── file3.cut
        └── file3.cut.bak

2 directories, 16 files
~/tmp$ find . -type f \( -name "*.cut" -o -name "*.cut.bak" \) -exec bash -c 'if [ -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").rec" -o -f "$(<<< "{}" sed "s/\(.*\/[^.]*\).*/\1/").mpg" ]; then rm "{}"; fi' \;
~/tmp$ tree
.
└── dir1
    ├── file1.rec
    ├── file2.mpg
    ├── file3.cut
    ├── file3.cut.bak
    └── subdir1
        ├── file1.rec
        ├── file2.mpg
        ├── file3.cut
        └── file3.cut.bak

2 directories, 8 files

보시다시피 확장자를 가진 모든 파일 .cut이나 .bak이름과 확장자가 같은 파일 또는 .rec기존 .mpg파일이 반복적으로 삭제됩니다( file1.cut따라서 file1.cut.bak삭제되고 file1.rec삭제 되며 file2.cut동일한 디렉토리에 파일이 없기 때문에 삭제 되지 않거나 ).file2.cut.bakfile2.mpgfile3.cutfile3.cut.bakfile3.recfile3.mpg

답변2

명령과 셸이 매우 제한된 일부 작은 내장 장치에서 명령을 실행해야 하는 경우(예: 누락 find, 최소 셸 à la sash) 가능한 접근 방식 중 하나는 이를 수행하기 위한 작은 C(또는 C++) 프로그램을 작성하는 것입니다. 프로그램을 실행 파일로 컴파일합니다(프로그램을 자유 소프트웨어로 만드는 것이 좋습니다).

당신은 사용할 것이다온라인 TV파일 트리를 재귀적으로 탐색하고 삭제할 경로의 배열(또는 벡터 또는 목록)을 만듭니다. 그런 다음 두 번째 단계에서는 파일이 효과적으로 삭제됩니다. 관련 기능은인터넷 TV(3)(파일 트리 탐색),snprintf(3)(구성 파일 이름),방문(2)(파일이 존재하는지 테스트),통계(3)(파일에 대한 유형, 크기 및 기타 메타데이터 가져오기)삭제(3)(파일 삭제),기본 이름(3), 등.

GNU가 있는 경우 find이를 사용하여 쉘 스크립트를 만들 수 있습니다(그러나 세부 사항은 실제 쉘에 따라 다를 수 있으며, 특히 POSIX와 호환되지 않을 만큼 작은 경우). 삭제할 파일명을 임시파일로 모아둡니다. 그런 다음 나중에 삭제하세요.

쉘 솔루션을 고집하고 GNU find를 사용할 수 있다고 가정하면 몇 가지 쉘 스크립트가 있을 수 있습니다.

먼저, 우리가 명명한 쉘 스크립트(외부에서 호출)는 임시 파일을 생성한 다음 clean-the-mess.sh각 & 파일에 대해 다른 내부 쉘 스크립트를 호출합니다.consider-cleaning.sh.cut.cut.bak

#!/bin/sh
## untested clean-the-mess.sh script
## a temporary file listing files to remove
cleanlistfile=$(tempfile -s .cleanlist)
## on exit, or SIGQUIT, SIGTERM, or SIGINT signal, remove it
trap "rm $cleanlistfile" EXIT QUIT TERM INT
## find every file name .cut | .cut.bak; run consider-cleaning.sh on it
find -type f \( -name '*.cut' -o 'name '*.cut.bak' \) \
    -exec consider-cleaning.sh '{}' $cleanlistfile \;
## remove the collected file list
for f in $(cat $cleanlistfile) ; do rm $f ; done

일부 파일 이름에 공백이 포함되어 있으면 이 방법이 작동하지 않습니다. 어쩌면 당신은 고려할 수 있습니다xargs(1)

consider-cleaning.sh 그런 다음 정리할 파일 목록에 파일 경로를 추가하는 내부 스크립트를 작성해야 합니다 . 그럴 수도 있다

#!/bin/sh
# internal untested consider-cleaning.sh script
file=$1
collectlist=$2
case $file in 
 *.cut) 
   bas=$(basename $file .cut)
   if [ ! -f "$bas.rec" -a ! -f "$bas.mpg" ]; then
      echo $file >> $collectlist
   fi
 ;;
 *.cur.bak)
   bas=$(basename $file .cut.bak)
   if [ ! -f "$bas.rec" -a ! -f "$bas.mpg" ]; then
      echo $file >> $collectlist
   fi
 ;;
 esac

내 스크립트는 입증되지 않았고 테스트되지 않았으므로 잘못되었을 수 있습니다. #!/bin/sh -vx이를 테스트하고 디버그하기 위한 첫 번째 줄로 사용합니다 (일부 실행 추적을 얻을 수 있습니다).

또는 작은 삽입루아인터프리터는 몇 가지 기본 원시 파일 관련 작업을 수행하고 Lua에서 스크립트를 작성합니다. Lua는 삽입하기가 매우 쉽고 작은 통역사가 될 수 있습니다.

관련 정보