【问题标题】:Deleting all folders that aren't linked in a directory with bash使用 bash 删除目录中未链接的所有文件夹
【发布时间】:2012-05-04 16:35:50
【问题描述】:

我有一项任务要求我删除目录中未符号链接的所有文件夹,只保留符号链接的文件夹和符号链接。

如果我有 3 个资源:链接、链接文件夹和未链接文件夹。链接和linked_folder将被保留。

目前我已经设法得到这个代码,它适用于我们拥有的文件命名结构,但我想知道是否有更清洁的解决方案?

protected_folders=`ls -l | awk '/^l/ {printf $10}' | tr '/' '|'`;
symlinks=`ls -l | awk '/^l/ {print $8}' | tr "\n" "|"`;
protected_resources=$protected_folders$symlinks;
protected_resources=${protected_resources:0:${#protected_resources}-1};
folders_to_delete=`ls | grep -v -E "$protected_resources"`; 
echo $folders_to_delete | tr '\n' ' ' | tr ' ' '\000' | xargs -0 rm -rf

我知道上面的命令可以在一行中完成,但我已经将它分开了,因为我被要求让它更“可读”。

任何帮助将不胜感激。

【问题讨论】:

    标签: bash directory symlink


    【解决方案1】:

    将符号链接及其目标移动到新目录可能更容易,然后用新目录替换旧目录。

    警告:这只是一个粗略的草图,仅供您参考。 [更新:清理并使其不像伪代码]

    # Make an empty directory to hold the symlinks and targets
    # that you want to keep
    DIR_TO_CLEAN=/the/directory/to/clean/up
    TMP_DIR=$(mktemp -d)
    
    for x in $DIR_TO_CLEAN/*; do
        # Move each symlink and its target to the new directory
        [[ -h $x ]] && mv $x $(readlink -f $x) $TMP_DIR
    done
    
    # FIRST!!!, confirm that $TMP_DIR has everything you want to keep,
    # and $DIR_TO_CLEAN has nothing you want to keep
    rm -rf $DIR_TO_CLEAN
    mv $TMP_DIR $DIR_TO_CLEAN
    

    【讨论】:

      【解决方案2】:

      您可以找到所有要保留的目录,如下所示:

      keep_me=$(for link in $(find . -type l); do find -L . -samefile $link; done)
      

      您可以将它与@chepner 的解决方案结合起来,如下所示:

      mkdir ../new_tmp_dir
      for link in $(find . -type l) 
      do
          find -L . -samefile $link -print0
      done | xargs -0 -I{} mv {} ../new_tmp_dir
      rm -rf *
      mv ../new_tmp_dir/* .
      

      如果您移动的目录深度超过一层,您可能需要修改查找语句(使用-maxdepth=1)。

      【讨论】:

        【解决方案3】:

        我不知道你是否会称它为更干净、优雅或复杂得离谱。设置很多,但最后几行“实际工作”已经足够清晰了。

        # map - apply a function to all arguments
        map() {
          fn="$1"
          shift
          for x in "$@"; do
            $fn $x
          done
        }
        
        echoif() { if $1 "$2" ; then echo $2 ; fi }
        
        # use map/echoif to find items that meet a criteria in a list
        filter() {
          op=$1
          shift
          map "echoif $op" "$@"
        }
        
        # list grep, essentially
        find_in_list() {
          item=$1
          shift
          itemis() { test $item == $1 ; }
          res=`filter itemis "$@"`
          test -n "$res"
        }
        
        not() { if $* ; then return 1; fi ; }
        not_in_list() { not find_in_list $* ; }
        
        # utility functions for filtering
        islink() { test -L $1 ; }
        isdir() { test -d $1 ; }
        
        # actual work starts here
        links=`filter islink *`
        dests=`map readlink $links`
        
        should_delete() { not_in_list $1 $links $dests ; }
        
        dirs=`filter isdir *`
        todelete=`filter should_delete $dirs`
        
        # you know what to do here    
        echo rm -rf $todelete
        

        【讨论】:

          【解决方案4】:

          这是一种可能的解决方案,只需运行

          mkdir "./onlylinkedfiles" && cd "./onlylinkedfiles"
          tar -ch "../symlinks" | tar -x --strip-components=1
          

          你只得到了当前目录中../symlinks/中符号链接的所有文件和目录。

          与一些自动化相同:

          cd "delete_here"
          f="../symlinkshere"; mkdir ../temporary && pushd ../temporary && tar -vch "${f}" | tar -x --strip-components=1 && rm -rf "`dirs +1`" && cd .. && mv temporary "`dirs +1`" && popd
          

          在该当前目录之后仅包含在../symlinkshere/ 获得符号链接的文件。

          让我们分解一下:

          # Specify directory where symlinks are:
          f="../symlinkshere"; 
          # Create temporary directory:
          mkdir ../temporary && 
          # Remember current and change cwd to temporary folder:
          pushd ../temporary && 
          # Copy all symlinked files and directories to cwd:
          tar -vch "${f}" | tar -x --strip-components=1 && 
          # Remove directory where we been when pushd called:
          rm -rf "`dirs +1`" && 
          # Cd out of temporary dir:
          cd .. && 
          # Rename temporary to original cwd
          mv temporary "`dirs +1`" && 
          # Go back to path where we started:
          popd
          

          这里是方便使用的shell脚本:

          它适用于当前目录并接受一个参数,即符号链接的路径。
          cd /path/to/clean
          replacebylinks.sh /here/is/symlinks/

          文件:~/bin/replacebylinks.sh

          #!/bin/bash
          tmp="`mktemp -d`"
          sourced="`readlink -f ${1}`"
          workd="`pwd -P`"
          
          cd "${tmp}"
          tar -vchC "${sourced}" . | tar -xv --strip-components=1
          
          rm -vrf "${workd}"
          cd ..
          mv -v "${tmp}" "${workd}" && cd "${workd}"
          

          一些注意事项:

          • 如果您认为输出过多,可以从命令中删除详细开关 -v
          • 使用tar -chC "source" . 可能会更好,因为没有-C source 整个源目录树都保留在目标位置。对于绝对路径,这从 / root 开始。

          【讨论】:

          • 我不明白这如何保留具有指向它们的符号链接的目录...
          • 也许我误解了.. 所以你希望那些有指向它们的符号链接的普通目录被保留,而其他没有任何指向它们的符号链接的目录被删除?
          • @shellter:根据我对 Danger 描述的阅读,我相信链接到的目录和符号链接都位于同一个目录中......我认为我们不需要担心链接指出当前目录结构。
          • @BartonChittenden :对不起,你不是 O.P. 我以为你是。哇!我正在删除我上面的​​评论,以减少在这个线程上的喋喋不休。对不起!
          • 是的,巴顿是正确的,我想保留所有具有指向它们的符号链接的文件夹。为了让您更好地了解原因,我们有指向我们当前和以前版本的符号链接,并且在清理时应删除当前或以前的任何内容。
          猜你喜欢
          • 2013-07-31
          • 1970-01-01
          • 1970-01-01
          • 2010-11-12
          • 2012-07-01
          • 2010-11-20
          • 1970-01-01
          • 2022-07-16
          相关资源
          最近更新 更多