Я должен иметь дело с большим количеством файлов, вложенных в каталогах (один файл на каталог), напоминая что-то вроде этого:
fred/result.txt
john/result.txt
mary/result.txt
...
Я в настоящее время использую следующую команду для обработки каждого из тех файлов:
find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c \"cd '{}' && processResult result.txt\" \;
Я ищу что-то, что я могу добавить в конец этой команды, которая изменит имена файлов на fred.txt
, и т.д. и затем более позднее перемещение файл в родительский каталог для устранения дополнительного слоя каталогов.
Каков был бы лучший способ сделать это?
Мы можем использовать классический подход: find
с while read
комбинация:
Демонстрация:
$ ls *
fred:
results.txt
jane:
results.txt
john:
results.txt
$> find . -type f -name "results.txt" -printf "/%P\n" | while read FILE ; do DIR=$(dirname "$FILE" );\
> mv ."$FILE" ."$DIR""$DIR".txt;done
$> ls
fred/ jane/ john/
$> ls *
fred:
fred.txt
jane:
jane.txt
john:
john.txt
Использовать echo
перед использованием mv
протестировать строку с Вашими файлами.
Незначительное улучшение
Мы можем встроить вызов в bash
в должностное лицо, с расширением параметра (конкретно удаление префикса). В основном это встраивает сценарий в исполнительный вызов.
$> find "$PWD" -type f -name "results.txt" -exec bash -c ' DIR=$( dirname "{}" ); echo "{}" "$DIR"/"${DIR##*/}".txt ' \;
/home/xieerqi/TESTDIR/fred/results.txt /home/xieerqi/TESTDIR/fred/fred.txt
/home/xieerqi/TESTDIR/jane/results.txt /home/xieerqi/TESTDIR/jane/jane.txt
/home/xieerqi/TESTDIR/john/results.txt /home/xieerqi/TESTDIR/john/john.txt
Сделать команду общей, (работающий на любой файл, не просто results.txt
) просто удалите -name "results.txt"
часть. Также см. это сообщение для альтернативного решения Python этого.
Выполнение его через находку кажется чрезмерно сложным. Почему бы не использовать простое для цикла?
for folder in *; do
(cd "$folder" && processResult result.txt) # This replaces your previous find(1)
mv "$folder/result.txt" "${folder}.txt"
rmdir "$folder"
done
Я думаю, что это законно (использование находящегося в perl rename
команда)
find dir -name 'results.txt' -exec rename -nv -- 's|/(.*)/(.*)$|/$1/$1.txt|' {} +
например, данный
$ tree dir
dir
├── fred
│ └── results.txt
├── john
│ └── results.txt
└── mary
└── results.txt
3 directories, 3 files
затем
$ find dir -name 'results.txt' -exec rename -v -- 's|/(.*)/(.*)$|/$1/$1.txt|' {} +
dir/fred/results.txt renamed as dir/fred/fred.txt
dir/john/results.txt renamed as dir/john/john.txt
dir/mary/results.txt renamed as dir/mary/mary.txt
получающийся в
$ tree dir
dir
├── fred
│ └── fred.txt
├── john
│ └── john.txt
└── mary
└── mary.txt
3 directories, 3 files
Если только необходимо пойти 1 уровень ниже dir
, Вы можете просто делать
rename -vn -- 's|/(.*)/(.*)$|/$1/$1.txt|' dir/*/results.txt
Как всегда, -n
опция оставлена внутри для тестирования
Маленький сценарий Python ниже сделает точно, как Вы описываете; это будет:
results.txt
, согласно его превосходящему каталогуРезультат:
Это:
directory
|
├── fred
│ └── results.txt
├── john
│ └── results.txt
└── mary
└── results.txt
станет:
directory
|
├── fred.txt
│
├── john.txt
│
└── mary.txt
#!/usr/bin/env python3
import shutil
import os
import sys
dr = sys.argv[1]
for root, dirs, files in os.walk(dr):
for file in files:
if file == "results.txt":
spl = root.split("/"); newname = spl[-1]; sup = ("/").join(spl[:-1])
shutil.move(root+"/"+file, sup+"/"+newname+".txt"); shutil.rmtree(root)
move_rename.py
Выполните его командой:
python3 /path/to/move_rename.py <directory_to_reorganize>
как всегда, сначала протестируйте его на небольшой выборке
Если у Вас будет несколько файлов в папках с теми же расширениями, то некоторые вышеупомянутые команды перезапишут все кроме одного, переименовывая все файлы с тем же именем.
folder1/file1.txt file2.txt --> folder1/folder1.txt
Для предотвращения этого можно использовать эту команду или эквивалентный:
for f in */*.txt ;do fp=$(dirname "$f"); fl=$(basename "$f"); mv "$fp/$fl" "$fp/$fp"_"$fl"; done
Путем хранения полного $fl имени файла, а не просто расширения, Вы сохраняете все файлы.
folder1/file1.txt file2.txt --> folder1/folder1_file1.txt folder1_file2.txt