Как переместить все файлы из нескольких каталогов в их родительские каталоги с помощью bash

Как переместить все файлы из нескольких каталогов в их родительские каталоги с помощью bash

У меня следующая структура файла:

  • /главная/данные/C01/dir_wwe_346/file1.txt pic.jpg случайный.sh
  • /главная/данные/C02/dir_wwe_644/file1.txt pic.jpg случайный.sh
  • /главная/данные/C03/dir_wwe_324/file1.txt pic.jpg случайный.sh

Я хочу, чтобы они были такими:

  • home/data/C01/file1.txt pic.jpg случайный.sh
  • home/data/C02/file1.txt pic.jpg случайный.sh
  • home/data/C03/file1.txt pic.jpg случайный.sh

По сути, это перемещение нескольких файлов на один каталог вверх. Я пробовал этот скрипт, но безуспешно:

#!/bin/bash for i in */ do cd i/*/ mv * ../ done


После публикации этого (но до прочтения ответа Grawity ниже) я понял, что не использовал правильное расширение переменной, и запустил это:

#!/bin/bash for i in */ do cd ${i}*wwe* mv * ../ done

Скрипт перемещает все подкаталоги в папку данных, поэтому в итоге получается следующее:

  • /дом/С01/dir_wwe_346/file1.txt pic.jpg случайный.sh
  • /дом/С02/dir_wwe_644/file1.txt pic.jpg случайный.sh
  • /дом/С03/dir_wwe_324/file1.txt pic.jpg случайный.sh

    Что я делаю не так?


P.S. Я отредактировал пост, чтобы он показывал процесс, через который я прошел, и чтобы ответы были более осмысленными для новичков, которым они могут быть полезны. Спасибо, grawity, я узнал что-то новое. Я только неделю назад начал изучать bash и чувствую, что прогрессирую.

решение1

  1. Переменные распознаются и расширяются только с $префиксом. Если цикл определяет переменную 'i', вам нужно использовать$iкогда вам нужно его значение:

    for i in */; do
        cd $i/*/
    
  2. "Текущий каталог" распространяется на весь процесс и не сбрасывается автоматически на каждой итерации цикла. Вам нужно либо вручную вернуться в родительский каталог после этого:

    cd $i/*/; mv * ../; cd ../../
    

    или используйте «подоболочку» для определения области изменения каталога:

    (cd $i/*/; mv * ../)
    
  3. Вы не делаете никакой проверки ошибок. Если cdкогда-либо не удается, последующее mvможет сделать неприятные вещи. Либо объединяйте команды с помощью &&, либо делайте противоположную проверку и используйте || exit(или || break), в зависимости от того, что выглядит лучше:

    for i in */; do
        cd $i/*/ && {
            mv * ../;
            cd ../../
        }
    done
    
    for i in */; do
        cd $i/*/ || exit
        mv * ../
        cd ../../
    done
    
    for i in */; do
        (cd $i/*/ && mv * ../)
    done
    
  4. Улучшение: можно переместить подстановочный знак подкаталога в mv, что позволит ему работать даже в случае наличия нескольких подкаталогов:

    cd $i/ || exit
    mv */* .
    cd ../
    
  5. Улучшение: Вы можете сделать это, не прибегая к cdследующим мерам:

    mv $i/*/* $i/
    

Связанный контент