Как я могу поместить файлы в подкаталоги, основываясь на имени файла, используя bash? - PullRequest
0 голосов
/ 11 февраля 2020

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

Примеры файлов:

2020_Documents_Bills_Water Bill.pdf
2020_Documents_Taxes_W2.pdf
2020_Documents_Receipts_Store Name_Groceries.pdf
2020_Pictures_Family Trip_California_Disney Land_Family Pic.jpg

Таким образом, файл 2020_Documents_Bills_Water Bill.pdf будет иметь вид 2020/Documents/Bills/Water Bill.pdf.

Я хотел бы ограничить используемые инструменты bash, sed, grep, mkdir и mv, если это возможно.

У меня были некоторые мысли о том, как, по моему мнению, должен выполняться скрипт, но я не знаю, как заставить его рекурсивно получать подкаталоги без большого количества отвратительных if операторов. Я думал, что этот код, вероятно, мог бы получить первый subdir и поместить его в массив, а затем удалить этот текст и подчеркивание, которое следует за ним из имени файла, и затем повторять итерацию до тех пор, пока не заканчиваются подчеркивания.

#!/bin/bash

# cd to directory where files are located
cd /directory/with/files

# iterate over files in directory
for file in *; do
  subDirs=() # empty array for subdirs
  filePath="" # empty string to build filepath

  # ------------------------------------------------------------
  # code to extract subdir names and add to subDirs array
  # ------------------------------------------------------------

  # build filepath using string of all subdirs
  for i in ${!subDirs[@]}; do
    filepath="${filePath}/${subDirs[$i]}"
  done

  # set filename to text after last underscore
  filename=${file##*_}

  # make filepath based on subdirs
  mkdir -p "${filepath}"

  # move file into filepath without subdirs in name
  mv ${file} "${filepath}/${filename}"

done

Ответы [ 2 ]

3 голосов
/ 11 февраля 2020

Вы можете сделать это проще, потому что mkdir -p path/to/yours работает только с одним вызовом. Вам не нужно рекурсивно создавать подкаталоги по одному.
Не могли бы вы попробовать:

cd /directory/with/files        # cd to directory where files are located

for file in *; do
    [[ -f $file ]] || continue  # skip non-file entries (just in case)
    dir=${file%_*}
    base=${file##*_}

    dir=${dir//_/\/}            # replace "_"s with "/"s
    mkdir -p "$dir"
    mv -- "$file" "$dir/$base"
done

[Строгая версия]
Приведенный ниже скрипт выполняет проверку имена файлов (с помощью jhn c).

for file in *; do
    [[ -f $file ]] || continue  # skip non-file entries (just in case)
    dir=${file%_*}
    base=${file##*_}

    dir=${dir//_//}             # replace "_"s with "/"s

    # validate filenames
    case "/$dir/" in
        */../* | */./* | //*)   # $dir contains extra dot(s)
            echo "skipping invalid filename: $file"
            continue
            ;;
    esac
    if [[ -z $base ]]; then     # the filename ends with "_"
        echo "skipping invalid filename: $file"
        continue
    fi

    mkdir -p "$dir"
    mv -- "$file" "$dir/$base"
done

Результат:

/directory/
└── with
    └── files
        └── 2020
            ├── Documents
            │   ├── Bills
            │   │   └── Water Bill.pdf
            │   ├── Receipts
            │   │   └── Store Name
            │   │       └── Groceries.pdf
            │   └── Taxes
            │       └── W2.pdf
            └── Pictures
                └── Family Trip
                    └── California
                        └── Disney Land
                            └── Family Pic.jpg
0 голосов
/ 11 февраля 2020

Просто добавьте одну заметку cd /directory/with/files

Без exit. Предполагая, что /directory/with/files не существует.

#!/bin/bash

# cd to directory where files are located
cd /directory/with/files

printf '%s\n' 'rm this' 'rm that' 'mv this' 'mv that'

на выходе получается

myscript: line 4: cd: /directory/with/files: No such file or directory
rm this
rm that
mv this
mv that

весь код после cd выполняется / все еще выполняется!

С exit и при условии, что /directory/with/files не существует.

#!/bin/bash

# cd to directory where files are located
cd /directory/with/files || exit

printf '%s\n' 'rm this' 'rm that' 'mv this' 'mv that'

Вывод.

myscript: line 4: cd: /directory/with/files: No such file or directory

Сценарий завершился и не выполнил остальную часть кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...