Вопрос Переименуйте файл в имя родительского каталога в терминале


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

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
2018-03-16 21:18


происхождения


Обратная косая черта в имени файла не допускается. Лучше всего будет использовать символ подчеркивания или какой-либо другой специальный символ. Это довольно легко для скрипта, из того, что я вижу - Sergiy Kolodyazhnyy
@Serg Извините, я имел в виду переименование в 'fred.txt' еще в папке 'fred' - я отредактирую вопрос, чтобы сделать эту часть более четкой. - DTR
ОК. Поэтому дайте мне понять это правильно. Мы имеем, например /home/user/some_tests/fred/results.txt , Вы хотите, чтобы это стало /home/user/some_tests/fred.txt , Верно? - Sergiy Kolodyazhnyy
@Serg Да, хотя на этом этапе происходит /home/user/some_tests/fred/results.txt в /home/user/some_tests/fred/fred.txt будет приемлемым - DTR
ОК. Любое предпочтение на языке сценариев? Опубликует позже. Я нахожусь в классе atm - Sergiy Kolodyazhnyy


ответы:


Мы можем использовать классический подход: 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 в exec, с расширением параметра (в частности, удаление префикса). В основном это встраивание скрипта в вызов exec.

$> 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
2018-03-16 22:53





Я думаю, что это законно (используя perl-based 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
2018-03-16 22:33





Маленький скрипт 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
2018-03-16 21:55





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

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
2018-03-17 00:56





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

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

1
2017-10-28 09:55