如何将包含匹配模式的文件的目录移动到另一个目录?

如何将包含匹配模式的文件的目录移动到另一个目录?

我有多个分层子目录,并且我试图将包含模式文件的所有目录重新定位到新的父目录中。我想维护我想要移动的目录的内容,无论它们除了匹配模式的文件之外是否还有文件。

例如:

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.这个版本需要 GNUfind或类似的支持-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包含subsubdir/a.pngb.png,您将被subsubdir移动到 之前subdir,因此它们成为目标目录中的对等体,而不是分层目录。

如果这没有达到您所需的结果,您可以尝试删除,但是在尝试下降到已移动的目录的遍历过程中-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

相关内容