Переименуйте файл к названию родительского каталога в терминале

Я должен иметь дело с большим количеством файлов, вложенных в каталогах (один файл на каталог), напоминая что-то вроде этого:

fred/result.txt
john/result.txt
mary/result.txt
...

Я в настоящее время использую следующую команду для обработки каждого из тех файлов:

find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c \"cd '{}' && processResult result.txt\" \;

Я ищу что-то, что я могу добавить в конец этой команды, которая изменит имена файлов на fred.txt, и т.д. и затем более позднее перемещение файл в родительский каталог для устранения дополнительного слоя каталогов.

Каков был бы лучший способ сделать это?

5
задан 16 March 2016 в 14:30

5 ответов

Мы можем использовать классический подход: 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 этого.

2
ответ дан 23 November 2019 в 08:43

Выполнение его через находку кажется чрезмерно сложным. Почему бы не использовать простое для цикла?

for folder in *; do
    (cd "$folder" && processResult result.txt)  # This replaces your previous find(1)
    mv "$folder/result.txt" "${folder}.txt"
    rmdir "$folder"
done
2
ответ дан 23 November 2019 в 08:43

Я думаю, что это законно (использование находящегося в 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 опция оставлена внутри для тестирования

4
ответ дан 23 November 2019 в 08:43

Маленький сценарий 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>
    

Примечание:

как всегда, сначала протестируйте его на небольшой выборке

4
ответ дан 23 November 2019 в 08:43

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

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
2
ответ дан 23 November 2019 в 08:43

Другие вопросы по тегам:

Похожие вопросы: