패턴과 일치하는 파일이 포함된 디렉터리를 다른 디렉터리로 이동하는 방법은 무엇입니까?

패턴과 일치하는 파일이 포함된 디렉터리를 다른 디렉터리로 이동하는 방법은 무엇입니까?

계층적 하위 디렉터리가 여러 개 있고 패턴 파일이 포함된 모든 디렉터리를 새 상위 디렉터리로 재배치하려고 합니다. 패턴과 일치하는 파일 외에 파일이 있는지 여부에 관계없이 이동하려는 디렉터리의 내용을 유지하고 싶습니다.

예를 들어:

homedir/subdir/{file.txt, file.png, file.rtf}
homedir/subdir/{file.txt, file.png}
homedir/subdir/{file.txt, file.jpg}
homedir/subdir/subdir/{file.png, file.png, file.mp3}

"*.png"(및 디렉토리에 있을 수 있는 기타 모든 비png 콘텐츠)를 포함하는 모든 디렉토리를 /dirPNG로 이동하고 싶습니다.

따라서 결과는 다음과 같습니다.

homedir/subdir/{file.txt, file.jpg}
homedir/dirPNG/subdir/{file.txt, file.png, file.rtf}
homedir/dirPNG/subdir/{file.txt, file.png}
homedir/dirPNG/subdir/subdir/{file.png, file.png, file.mp3}

답변1

중첩된 버전을 사용할 수 있습니다 find. 이 버전에는 and를 find지원하는 GNU 또는 유사 항목이 필요합니다 .-maxdepth-quit해결책사용될 수 있다POSIX호환성.

find homedir -depth -type d \
    -exec sh -c '[ -n "$(find "$@" -maxdepth 1 -type f -name "*.png" -print -quit)" ]' _ {} \; \
    -exec sh -c 'echo "Move $@"' _ {} \;

있을 때 교체하거나 echo "Move $@"보충하십시오 .mv "$@" /dirPNG절대적으로 확실하다코드가 원하는 작업을 수행하고 있습니다.

먼저 디렉터리를 깊이 탐색하여 *.png각 디렉터리에서 일치하는 파일을 검색하는 방식으로 작동합니다. 일치하는 항목이 있으면 디렉터리가 이동됩니다.

homedir/subdir따라서 include subsubdir/a.png및 가 있는 경우 이전으로 이동하여 b.png계층 적 디렉터리가 아닌 대상 디렉터리의 피어가 됩니다.subsubdirsubdir

원하는 결과를 얻지 못한 경우 삭제를 시도할 수 있지만 이동된 디렉터리 탐색으로 내려가려고 할 때 -depth많은 유형 오류가 발생합니다 . 이는 치명적이지는 않지만 매우 우아하지 않습니다.find: ‘subdir’: No such file or directoryfind

그럼에도 불구하고 디렉터리를 대상으로 이동하려고 하면(동일한 이름의 디렉터리가 이미 존재하는 경우) 오류가 발생합니다. 이 경우 어떤 일이 발생해야 하는지 지정하지 않았으므로 오류가 발생하고 이동이 거부되는 것으로 충분합니다.

답변2

다음은 필요한 작업을 수행하는 스크립트입니다.현재 하고 있는 작업을 홈 디렉터리에 적용하면 위험하다는 점에 유의하세요.

아래 스크립트배치 파일 만들기작업을 수행합니다.

이를 통해사전에 예상되는 조치를 검토하세요.실제로 문제를 일으킬 수 있는 행을 삭제할 수 있도록 작업을 수행합니다.

스크립트에는 향후 확장 기능을 위해 고려해볼 것을 권장하는 다른 설명이 있습니다.

#!/bin/sh

BASE=`basename "$0" ".sh" `
TMP="/tmp/tmp.$$.${BASE}"       ; rm -f ${TMP}

START=`pwd`
BATCH="${START}/${BASE}.batch"

MODE=0
INSENS=0
ONE_PARTITION=""
while [ $# -gt 0 ]
do
    case "${1}" in
        "--suffix" ) MODE=1 ; STRNG="${2}" ; pattern_ident="RELOC_${STRNG}" ; shift ; shift ;;
        "--prefix" ) MODE=2 ; STRNG="${2}" ; pattern_ident="RELOC_${STRNG}" ; shift ; shift ;;
        "--single" ) ONE_PARTITION="-xdev" ; shift ;;
        "--insensitive" ) INSENS=1 ; shift ;;
        * ) echo "\n\t ERROR:  Invalid option used on command line.  Options allowed: [ --suffix | --prefix ] \n Bye!\n" ; exit 1 ; ;;
    esac
done

if [ ${MODE} -eq 0 -o -z "${STRNG}" ] ; then  echo "\n\t ERROR:  Must specify one of --suffix or --prefix values on the command line.\n Bye!\n" ; exit 1 ; fi

SEARCH_ROOT="${HOME}"
RELOCN_DIR="${HOME}/${pattern_ident}"

if [ ! -d "${RELOCN_DIR}" ]
then
    mkdir "${RELOCN_DIR}"
    if [ $? -ne 0 ] ; then  echo "\n\t ERROR:  Unable to create target directory for directory relocation actions.\n Bye!\n" ; exit 1 ; fi

fi 2>&1 | awk '{ printf("\t %s\n", $0 ) ; }'

### Ignore start directory itself
### Handling directories with spaces/characters in their name
rm -f "${TMP}.search"*

### Segregate dot dirs from others
find "${SEARCH_ROOT}" -mindepth 1 -maxdepth 1 -type d -print | sort >"${TMP}.search.raw"
    awk -F \/ '{ if( index( $NF, "." ) == 1 ) { print $0 } ; }' <"${TMP}.search.raw" >"${TMP}.search"
    awk -F \/ '{ if( index( $NF, "." ) == 0 ) { print $0 } ; }' <"${TMP}.search.raw" >>"${TMP}.search"

##########
#more "${TMP}.search"
#exit 0
##########


while read SEARCH_dir
do
    if [ -z "${SEARCH_dir}" ] ; then  break ; fi

    echo "\t Scanning: ${SEARCH_dir} ..." >&2

    ### insert function to dynamically remap ${PAT} to expanded set for case insensitive
    if [ ${INSENS} -eq 1 ]
    then
        sPAT="[Pp][Nn][Gg]"
    else
        sPAT="${STRNG}"
    fi

##########
#echo "sPAT = ${sPAT}" >&2
#exit 0
##########

    case ${MODE} in
        1)  
#########
#( eval find \"${SEARCH_dir}\" ${ONE_PARTITION} -type f -name \'\*\.${sPAT}\' -print | awk -F'/[^/]*$' '{print $1}' | more >&2 ) <&2
#exit 0
#########

            eval find \"${SEARCH_dir}\" ${ONE_PARTITION} -type f -name \'\*\.${sPAT}\' -print |
                awk -F'/[^/]*$' '{print $1}' | sort | uniq
            ;;
        2)  
            eval find \"${SEARCH_dir}\" ${ONE_PARTITION} -type f -name \'${sPAT}\*\' -print |
                awk -F'/[^/]*$' '{print $1}' | sort | uniq
            ;;
    esac
done <"${TMP}.search" >"${TMP}.dirsToMove"
if [ ! -s "${TMP}.dirsToMove" ] ; then  echo "\n\t No directories identified for specified pattern. No action taken.\n Bye!\n" ; exit 0 ; fi

echo "\n Starting directory move ..."

#########
#more "${TMP}.dirsToMove"
#exit 0
########

###
### Doing the action direction without a specific visual review could corrupt
### the HOME directory to point of unusability if the wrong directories are acted upon.
###
### Save all action commands into a batch file for manual visual review
### to confirm sanity of actions identified before applying.
###
rm -f "${BATCH}"

while read DirToMove
do
    if [ -n "${DirToMove}" ]
    then
        new=`echo "${DirToMove}" | eval sed \'s\+${SEARCH_ROOT}/\+\+\' `
        echo "mv -fv \"${DirToMove}\" \"${RELOCN_DIR}/${new}\" " 2>&1 | awk '{ printf("%s\n", $0 ) ; }' >>"${BATCH}"
    fi
done <"${TMP}.dirsToMove"
if [ ! -s "${BATCH}" ] ; then  echo "\n\t No directories identified for specified pattern. No action taken.\n Bye!\n" ; exit 0 ; fi

echo "\n Directory move BATCH file was created:\n"
cat "${BATCH}" | awk '{ printf("\t %s\n", $0 ) ; }'
echo ""
wc -l "${BATCH}"


exit 0
exit 0
exit 0

관련 정보