Bash: перебрать файлы, перечисленные в текстовом файле, и переместить их

У меня есть каталог (каталог A) с 10 000 файлов. Я хочу переместить некоторые из них в каталог B, а другие в каталог C. Я создал текстовый файл, содержащий имена всех файлов, которые я хочу переместить в каталог B, и еще один с именами всех файлов, которые я хочу для перемещения в каталог C. Как я могу написать цикл bash для перемещения этих файлов в новые каталоги.

Псевдокод:

для файла в textfileB:
переместить файл из каталога A в каталог B

для файла в textfileC:
переместить файл из каталога A в каталог C

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

У меня есть что-то вроде этого, но я не мог заставить его работать:

FILES=[dont' know what goes here? An array? A list?  

Могу ли я просто указать имя текстового файла, и если да, то в каком формате должны быть файлы? имя1.расширение, имя2.расширение или имя1.расширение имя2.расширение]

for f in $FILES; do mv $f /B/$f [not sure about the second argument for mv]; done

Спасибо

Кстати, Mac OSX 10.6.8 (Snow Leopard) Apple Terminal v. 2.1.2/273.1 Bash 3.2


person PatentDeathSquad    schedule 04.07.2011    source источник


Ответы (6)


Запись часто задаваемых вопросов по BASH №1: "Как прочитать файл (поток данных, переменную) построчно ( и/или поле за полем)?"

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

person Ignacio Vazquez-Abrams    schedule 04.07.2011
comment
Этот BASH FAQ превосходен. Еще раз спасибо за то, что на него есть множество ссылок. :) - person sarnold; 04.07.2011

каталог скрипта должен быть вашим местоположением файлов

TO_B=file1.txt
TO_C=file2.txt

for file in $TO_B
do
mv ${file} B/
done

for file in $TO_C
do
mv ${file} C/
done
person Vijay    schedule 04.07.2011
comment
... перечислено в текстовом файле ... - person Ignacio Vazquez-Abrams; 04.07.2011
comment
Вам не хватает $(cat $TO_B)? - person sarnold; 04.07.2011
comment
@sarnold с использованием for i in $(cat $TO_B) не будет правильно обрабатывать имена файлов с пробелами. Это одна из причин, по которой я предпочитаю свой ответ, cat filename | while read i. - person asveikau; 04.07.2011

вы можете перемещать 1000 или 1000 пользовательских каталогов, не занимая много времени там, где существуют тысячи пользовательских каталогов.

cat deleteduser | while read i;  do mv -vv $i ../deleted_user; done; 
deleteuser= user name list
../deleted_user= destination dir
person Laxman Singh    schedule 11.04.2012

Вы должны использовать BASH? Как насчет Perl или Kornshell? Проблема здесь в том, что в Bash нет массивов с хэш-ключом (есть в Kornshell и Perl). Это означает, что нет простого способа отследить, какие файлы куда идут. Представьте в Perl:

my %directoryB;   #Hash that contains files to move to Directory B
my %directoryC;   #Hash that contains files to move to Directory C

open (TEXT_FILE_B, "textFileB") or die qq(Can't open "textFileB");
while (my $line = <TEXT_FILE_B>) {
    chomp $line;
    $directoryB{$line} = 1;
}
close TEXT_FILE_B;

open (TEXT_FILE_C, "textFileC") or die qq(Can't open "textFileC");
while (my $line = <TEXT_FILE_C>) {
    chomp $line;
    $directoryC{$line} = 1;
}
close TEXT_FILE_C;

Приведенные выше строки создают два хэша. Один для файлов, которые нужно переместить в каталог B, и один для файлов, которые нужно переместить в каталог C. Теперь все, что мне нужно сделать, это посмотреть на свой хэш и решить:

foreach my $file (@directory) { #A little cheating here...
   if (exists $directoryB{$file}) {
       move ($file, $directoryB);
   } elsif (exists $directoryC{$file}) {
       move ($file, $directoryC)
}

Мои операторы if теперь могут посмотреть, был ли определен ключ в этом хэше. Если это так, я знаю, что файл можно переместить в этот каталог. Мне нужно прочитать два текстовых файла только один раз. После этого мои два хэша будут хранить, какие файлы перемещаются в один каталог, а какие в другой.


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

ls | while read file
do
   if grep -q "^${file}$" textFileB
   then
       mv $file $directoryB
   elif grep -q "^${file}$" textFileC
   then
       mv $file $directoryC
   fi
done

grep -q выполнит поиск ваших двух текстовых файлов, чтобы увидеть, есть ли там соответствующий файл. Если это так, он переместит файл в этот каталог. Это не очень эффективно, так как каждый раз приходится искать весь текстовый файл. Тем не менее, это довольно эффективно, и вы говорите всего о 10 000 файлов, поэтому вся операция займет всего несколько минут.

person David W.    schedule 04.07.2011

Используя bash, имея огромный список файлов, содержащий строки с начальными и/или закрывающими пробелами, я бы предложил:

less 'file-list.txt' | while read -r; do mv "$REPLY" /Volumes/hard_drive_name/new_destination_directory_name; done

видеть:

person anon    schedule 21.02.2019

person    schedule
comment
Спасибо. Это сработало. Для других вот завершенная команда, которую я ввел в виде одной строки: cat list_of_files_with.txt | пока читал я; do mv $i /Volumes/имя_жесткого_диска/имя_нового_каталога_назначения; Выполнено - person PatentDeathSquad; 04.07.2011
comment
@AquaT33nFan — я бы поставил "$i" в кавычки, чтобы вы могли обрабатывать имена файлов с пробелами и другими символами, которые обычно не появляются в командной строке. - person asveikau; 04.07.2011
comment
Поздравляем, вы только что получили UUoCA. - person Fredrik Pihl; 04.07.2011
comment
@Fredrik - Действительно ли это бесполезно, если повышает читабельность? Я считаю, что что-то вроде (while read i; do whatever; done) < file-list.txt читается задом наперёд. Кроме того, дополнительные переключения контекста и загрузка двоичного файла cat будут довольно дешевыми, так как вы не заметите разницы на текущем оборудовании. - person asveikau; 04.07.2011
comment
@asveikau - бесполезно, возможно, здесь слишком сильное слово, но я бы сказал, что подход в вашем комментарии превосходит подход cat ... | . А поскольку *NIX — очень красивая ОС, вы же не хотите тратить процессы впустую, не так ли? ;-) - person Fredrik Pihl; 05.07.2011
comment
Кот мне больше понравился. Он читается как python, и я плохо знаю bash, о чем я и сказал в своем вопросе. Другой ответ (который, кажется, перенаправляет стандартный вывод) немного сложнее. Однако это заняло несколько минут, поэтому, если бы у меня было больше файлов, мне мог бы понадобиться способ с меньшим количеством процессов. Спасибо. - person PatentDeathSquad; 05.07.2011