Я почти закончил со скриптом, но это выводит каталоги. То, что я хотел бы иметь выходные данные файлов. В любом случае, один из вас, ребята, хочет мне помочь? :)

    #!bin/bash
( find /testftp/* -type d ;
  find /testftp/* -type f -iname DONOTDELETE.TXT -printf '%h'
) | sort | uniq -u

Выход:

/testftp/logs

Выходные данные - это каталог, в котором DONOTDELETE.TXT не существует. Это довольно близко. Просто нужно отобразить файлы.

3 ответа3

1

Думаю, я бы попробовал.


#!/bin/bash
# file name and path can not have spaces for this to work.

ignorefile=DONOTDELETE.TXT
dir="`find /testftp/* -type d`";
exists=$(ls $dir | for each in $(find $dir -type f -iname $ignorefile -printf '%h\n'); do echo -en "grep -v $each |" ; done | sed '$s/.$//') 
direxists=$(ls $dir | eval $exists | grep -v $ignorefile | sed 's/:/\//g' | sort | uniq -u)

for pth in $direxists; 
do 
if [ -d $pth ]; then 
if [ "$(ls -A $pth)" ]; then 
echo rm -f ""$pth*""
fi
fi
done

reproduce:
changed dir="`find /testftp/* -type d`";
to
dir="`find ./testftp/* -type d`";

mkdir testftp && cd testftp
for x in 1 2 3 4 5 6 7 8 9; do mkdir $x; done
for y in 1 2 3 4 6 7 9; do touch $y/blah; done
touch 5/DONOTDELETE.TXT
touch 5/some.log
touch 8/DONOTDELETE.TXT
touch 8/another.file

cd ..
$ ./script.sh 
rm -f ./testftp/1/blah
rm -f ./testftp/2/blah
rm -f ./testftp/3/blah
rm -f ./testftp/4/blah
rm -f ./testftp/6/blah
rm -f ./testftp/7/blah
rm -f ./testftp/9/blah

1

Вот мой взгляд на это:

#! /bin/bash

SPECIAL_FILE=DONOTDELETE
LOGFILE=clean.$(date +"%Y-%d-%m.%H%M%S").log   
FIND_BASE="$1"
if [ $# -ne 1 ]; then
        echo "Syntax $(basename $0) <FIND_BASE>"
        exit 1
fi
if [ "$FIND_BASE" = "." ]; then
        FIND_BASE=$(pwd)
else
        FIND_BASE=$(pwd)/$FIND_BASE
fi

for d in $(find $FIND_BASE -type d -print); do
        if [ "$d" != "$FIND_BASE" ]; then
                ls $d | grep $SPECIAL_FILE &> /dev/null
                if [ $? -ne 0 ]; then
                        echo "Deleting $d" | tee -a $LOGFILE
                        rm -rf $d 2>/dev/null
                else
                        echo "Ignoring $d, contains $SPECIAL_FILE" | tee -a $LOGFILE
                fi
        fi
done
exit 0

Добавьте это в сценарий, измените переменные в соответствии с вашим собственным соглашением об именах (для специального файла и имени журнала), а затем просто вызовите его с начальным путем к каталогу в качестве параметра. Он исключит любую директорию, содержащую нужный файл, и удалит все остальные.

0

Если у вас есть bash 4+ (проверьте с помощью bash --version), вы можете сделать это в две строки:

shopt -s globstar
for f in ./**/; do [[ -f "$f"/DONOTDELETE.TXT ]] || rm -f "$f"/*; done

Обратите внимание, что shopt -s globstar должен находиться на отдельной строке - не просто добавлять его к циклу for с помощью ; ,

./**/ расширяется до каждого подкаталога в текущем каталоге, и их подкаталоги рекурсивно. Если вы хотите пройти вниз по дереву только на один уровень, используйте вместо этого ./*/ (и не беспокойтесь о настройке globstar); если вам нужен более точный контроль, вам придется возиться с find (в частности, с -maxdepth и -mindepth ). Я использую ./**/ вместо **/ в случае, если любой из ваших каталогов начинается с -: это мешает их видеть как

[[ -f "$f"/DONOTDELETE.TXT ]] проверяет, существует ли этот файл и является ли он файлом (если вы хотите, чтобы он работал, даже если DONOTDELETE.TXT может отличаться от файла, используйте -e вместо -f). Строго говоря, вам не нужен / in, так как $ f содержит косую черту, но я думаю, что в этом случае она выглядит лучше, и в целом избыточные косые черты безвредны. || означает ИЛИ - если (и только если) этот тест оценивается как ложный, то будет выполнен код справа от него, в этом случае rm -f "$f"/* - который удаляет все файлы, кроме скрытых.

Если вы также хотите удалить скрытые файлы, вы можете использовать что-то вроде:

for f in ./**/; do [[ -f "$f"/DONOTDELETE.TXT ]] || rm -f "$f"/* "$f"/.*; done

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .