Как использовать Bash для удаления ненужных файлов / папок

#bash

#bash

Вопрос:

Я пытаюсь использовать скрипт bash для удаления некоторых нежелательных файлов с одинаковыми именами в разных каталогах, например: text1.txt существует в нескольких каталогах, и я хочу удалить его в каждом каталоге, в котором он существует.

Мне нужен скрипт для удаления ненужных файлов, а затем также для удаления каталога, в котором находится это имя файла ‘text1.txt ‘существует, поэтому, если он существует в папке с именем ‘TextFiles’, мне нужно, чтобы этот каталог папки был удален.

Это мой текущий код, над которым я работаю:

 for files in "/*"
do 
rm file.1txt file2.txt file3.txt
 

Мне немного любопытно, будет ли «/ *» просматривать все каталоги и работает ли «do» для удаления указанных файлов.

Кроме того, после использования ‘rm’ для удаления определенных файлов, как мне удалить каталог, в котором он существует.

Большое спасибо!

Ответ №1:

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

Теперь, когда я это сказал, представьте следующую файловую структуру:

 bhuiknei@debian:~/try$ tree
.
├── dir1
│   └── this.txt
└── dir2
    ├── dir3
    │   ├── this
    │   └── this.txt
    ├── notthis.txt
    └── this.txt

3 directories, 5 files
 

Для поиска и фильтрации определенных файлов find и grep — ваши друзья. Опция «-w» будет соответствовать только целым словам (поэтому notthis.txt не подобран):

 bhuiknei@debian:~/try$ find . | grep -w this.txt
./dir1/this.txt
./dir2/dir3/this.txt
./dir2/this.txt
 

Теперь, когда у нас есть все пути к файлам, они могут быть переданы в цикл while, где мы можем удалять файлы один за другим. Затем пустые каталоги можно удалить на втором шаге.

Я бы не советовал удалять содержащие папки принудительно, поскольку они могут содержать и другие файлы и папки.

Следующий скрипт выполняет трюк:

 #!/bin/bash

#Exiting if no file name was given
[[ $# -ne 1 ]] amp;amp; { echo "Specify a filename to delete in all sub folders"; exit 1; }

#Deleting files matching input parameter
echo "Deleting all files named ${1} in current and sub-directories."
find . | grep -w "$1" | 
    while IFS= read LINE; do
        rm -v "$LINE"
    done

#Deleting only-empty folders
rmdir -v *

exit 0
 

И результат:

 bhuiknei@debian:~/try$ tree
.
├── dir1
│   └── this.txt
├── dir2
│   ├── dir3
│   │   ├── this
│   │   └── this.txt
│   ├── notthis.txt
│   └── this.txt
└── script

3 directories, 6 files
bhuiknei@debian:~/try$ ./script this.txt
Deleting all files named this.txt in current and sub-directories.
removed './dir1/this.txt'
removed './dir2/dir3/this.txt'
removed './dir2/this.txt'
rmdir: removing directory, 'dir1'
rmdir: removing directory, 'dir2'
rmdir: failed to remove 'dir2': Directory not empty
rmdir: removing directory, 'script'
rmdir: failed to remove 'script': Not a directory
bhuiknei@debian:~/try$ tree
.
├── dir2
│   ├── dir3
│   │   └── this
│   └── notthis.txt
└── script

2 directories, 3 files
 

Также примечание: я не проверял, что произойдет, если рабочий каталог отличается от того, в котором находится скрипт, поэтому обязательно запустите его локально из родительского каталога или добавьте некоторую защиту. Решением может быть работа с абсолютными путями.

Удачи!

Комментарии:

1. Не уверен, почему вы хотели бы передать find в grep, когда у него есть собственный поиск по пути регулярного выражения

Ответ №2:

Вы знаете расширение имени файла и поэтому можете использовать это в цикле, анализируя вывод find с расширением параметра и так далее:

 find /path -name "file1.txt" | while read var
do 
     echo "rm -Rf ${var%/file1.txt}" # echo the command
     # rm -Rf "${var%/file1.txt}" # execute the command when sure that command list as expected
done 

${var%/file1.txt} -
 

расширит вывод из find и расширит вывод только до /file1.txt (каталог) rm -Rf затем принудительно удалит каталог вместе с файлом

В качестве альтернативы вы можете использовать printf изначально в find для печати только каталога без файла:

 find /path -name "file1.txt" -printf "%hn" | while read var
do 
     echo "rm -Rf $var" # echo the command
     # rm -Rf "$var" # execute the command when sure that command list as expected
done 
 

Комментарии:

1. Большое спасибо за ваше руководство, оно было чрезвычайно полезным. У меня есть несколько вопросов, если вы не возражаете, чтобы программа просматривала текущий каталог и другие каталоги и указывала более одного файла, это простой случай простого добавления этого, -find /* -name «file1.txt » «file2.txt » а затем в части » эхо » ‘${var%/file1.txt ,file2.txt }» или это неправильный путь?

2. Вы могли бы использовать find /* -name «file1.txt » -или -имя «file2.txt » тогда ${var%/*.txt}

3. Большое спасибо. Мне интересно, почему ‘-or’ используется вместо какого-то параметра ‘and’?

4. Поскольку для каждого файла, который проверяется find, он должен проверять наличие file1 или file2. Это никогда не может быть одновременно.

5. Спасибо, это имеет смысл, извините, если вы не возражаете, у меня есть последний вопрос, если бы я хотел удалить файл другого типа на своем компьютере, например, это файл .pdf, в части echo я просто делаю $ {var%/ * .txt, *.pdf} или использование запятой после первого файла не является правильным способом сделать это?