У меня следующая структура файла:
- /главная/данные/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
Переменные распознаются и расширяются только с
$
префиксом. Если цикл определяет переменную 'i', вам нужно использовать$i
когда вам нужно его значение:for i in */; do cd $i/*/
"Текущий каталог" распространяется на весь процесс и не сбрасывается автоматически на каждой итерации цикла. Вам нужно либо вручную вернуться в родительский каталог после этого:
cd $i/*/; mv * ../; cd ../../
или используйте «подоболочку» для определения области изменения каталога:
(cd $i/*/; mv * ../)
Вы не делаете никакой проверки ошибок. Если
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
Улучшение: можно переместить подстановочный знак подкаталога в
mv
, что позволит ему работать даже в случае наличия нескольких подкаталогов:cd $i/ || exit mv */* . cd ../
Улучшение: Вы можете сделать это, не прибегая к
cd
следующим мерам:mv $i/*/* $i/