Как я могу организовать файлы на основе их первой буквы в папках A-Z

@Oli был прав, это была просто проблема с микшером. По какой-то причине мой внутренний микрофон был установлен на «mute» по умолчанию.

Я исправил его, перейдя на вкладку «gnome-volume-control», «Input» и сняв флажок «mute». [!d1 ]

1
задан 10 January 2017 в 13:44

5 ответов

Code-golfed пока читается только двумя командами и двумя регулярными выражениями:

mkdir -p {a..z} '#'
prename -n 's|^[[:alpha:]]|\l$&/$&|;s|^[0-9]|#/$&|' [[:alnum:]]?*

Если у вас есть огромное количество файлов для перемещения, слишком много, чтобы вписаться в список аргументов процесса (да, есть предел, и это может быть всего несколько килобайт), вы можете сгенерировать список файлов с помощью другой команды и канала, чтобы prename, e. g.:

find -mindepth 1 -maxdepth 1 -name '[[:alnum:]]?*' -printf '%f\n' |
prename -n 's|^[[:alpha:]]|\l$&/$&|;s|^[0-9]|#/$&|'

Это имеет дополнительное преимущество, не пытаясь переместить буквальное имя файла [[:alnum:]]?*, если никакие файлы не соответствуют шаблону glob. find также допускает гораздо больше критериев соответствия, чем раскол оболочки. Альтернативой является установка опции оболочки nullglob и закрытие стандартного потока ввода prename .1

. В обоих случаях удалите переключатель -n, чтобы фактически переместить файлы, а не просто показать, как они

Добавление: вы можете снова удалить пустые каталоги с помощью:

rmdir --ignore-fail-on-non-empty {a..z} '#'

1 shopt -s nullglob; prename ... <&-

11
ответ дан 23 May 2018 в 02:34

Если вы не возражаете против zsh, функции и пары команд zmv:

mmv() {echo mkdir -p "${2%/*}/"; echo mv -- "$1" "$2";}
autoload -U zmv
zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'

Функция mmv делает каталог и перемещает файл. zmv затем предоставляет сопоставление и подстановку шаблонов. Во-первых, перемещая имена файлов, начинающиеся с алфавита, а затем все остальное:

$ zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
mkdir -p A/
mv -- abcd.ttf A/abcd.ttf
mkdir -p A/
mv -- ABCD.ttf A/ABCD.ttf
$ zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'
mkdir -p #/
mv -- 123.ttf #/123.ttf
mkdir -p #/
mv -- 七.ttf #/七.ttf

Запустите снова без определения echo в mmv для фактического выполнения перемещения.

8
ответ дан 23 May 2018 в 02:34

Я не разработал хороший способ сделать имена каталогов прописными буквами (или переместить файлы с прописными буквами), хотя вы могли бы сделать это впоследствии с помощью rename ...

mkdir {a..z} \#; for i in {a..z}; do for f in "$i"*; do if [[ -f "$f" ]]; then echo mv -v -- "$f" "$i"; fi; done; done; for g in [![:alpha:]]*; do if [[ -f "$g" ]]; then echo mv -v -- "$g" \#; fi; done
[d1 ] или более читаемо:

mkdir {a..z} \#; 
for i in {a..z}; do 
  for f in "$i"*; do
    if [[ -f "$f" ]]; then 
      echo mv -v -- "$f" "$i"; 
    fi 
  done
done
for g in [![:alpha:]]*; do 
  if [[ -f "$g" ]]; then 
    echo mv -v -- "$g" \#
  fi
done

Удалите echo после тестирования, чтобы фактически переместить файлы

И затем

rename -n 'y/[a-z]/[A-Z]/' *

удалите -n, если он хорошо выглядит после тестирования и запускается снова.

8
ответ дан 23 May 2018 в 02:34
  • 1
    Вы можете использовать if [[ -d "${i^}" ]] для создания переменной i capital и mkdir {A..Z} в начале. – Arronical 10 January 2017 в 15:04
  • 2
    Позвольте мне попробовать и посмотреть – Parto 10 January 2017 в 15:43
  • 3
    @Arronical спасибо! Однако я оставлю это, поскольку вы разместили его по-своему – Zanna 10 January 2017 в 15:53
  • 4
    @ Занне Мне нравится, что мы пришли к ней со всех сторон, итерации через буквы и их использование, поскольку критерии поиска мне никогда не приходили. Я уверен, что есть умное и быстрое решение с поиском, но я не могу его обвести! – Arronical 10 January 2017 в 17:38
  • 5
    Эй Занна, это не двигало шрифты, которые начинаются с прописной буквы. В противном случае работала нормально. – Parto 10 January 2017 в 17:48

Следующие команды в каталоге, содержащем шрифты, должны работать, если вы хотите использовать из-за пределов каталога хранения шрифтов, измените for f in ./* на for f in /directory/containing/fonts/*. Это очень основанный на оболочке метод, поэтому он довольно медленный и также нерекурсивный. Это создаст только каталоги, если есть файлы, которые начинаются с совпадающего символа.

target=/directory/to/store/alphabet/dirs
mkdir "$target"
for f in ./* ; do 
  if [[ -f "$f" ]]; then 
    i=${f##*/}
    i=${i:0:1}
    dir=${i^}
    if [[ $dir != [A-Z] ]]; then 
      mkdir -p "${target}/#" && mv "$f" "${target}/#"
    else
      mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir"
    fi
  fi
done

Как один лайнер, снова из каталога хранения шрифтов:

target=/directory/to/store/alphabet/dirs; mkdir "$target" && for f in ./* ; do if [[ -f "$f" ]]; then i=${f##*/}; i=${i:0:1} ; dir=${i^} ; if [[ $dir != [A-Z] ]]; then mkdir -p "${target}/#" && mv "$f" "${target}/#"; else mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir" ; fi ; fi ; done

Метод, использующий find с аналогичной строковой манипуляцией с использованием расширения параметра bash, который будет рекурсивным и должен быть несколько быстрее, чем версия чистой оболочки:

find . -type f -exec bash -c 'target=/directory/to/store/alphabet/dirs ; mkdir -p "$target"; f="{}" ; i="${f##*/}"; i="${i:0:1}"; i=${i^}; if [[ $i = [[:alpha:]] ]]; then mkdir -p "${target}/$i" && mv "$f" "${target}/$i"; else mkdir -p "${target}/#" && mv "$f" "${target}/#"; fi' \;

Или более читаемо:

[ f4]
7
ответ дан 23 May 2018 в 02:34
  • 1
    Этот тоже работал. Даже для прописных и строчных букв. – Parto 10 January 2017 в 18:01

Сопоставьте каждое имя файла с именем каталога с помощью tr, затем mkdir и mv:

find /src/dir -type f -print0 |
xargs -0 -I{} bash -c \
  'dir=/dest/$(basename "{}" | cut -c1 | tr -C "a-zA-Z\n" "#" | tr "a-z "A-Z"); mkdir -p $dir; mv "{}" $dir'
5
ответ дан 23 May 2018 в 02:34
  • 1
    Мне это очень нравится, это похоже на то, что я хватался за свое желание использовать находку. Есть ли способ создавать имена файлов верхнего регистра и перемещать в них имена файлов в нижнем регистре? – Arronical 10 January 2017 в 21:52
  • 2
    Я добавил еще tr для преобразования в верхний регистр. – xn. 10 January 2017 в 21:57
  • 3
    Почему обход через xargs просто для того, чтобы снова называть bash? Разве не было бы проще и гораздо более удобочитаемым, чтобы вывести вывод find в цикл while и read там он записывается по записи? – David Foerster 11 January 2017 в 00:08
  • 4
    Хороший вопрос, @DavidFoerster. Я предполагаю, что смещение против циклов в однострочном пространстве и предпочтение более функциональному подходу. Но скрипт bash в строке тоже не очень изящный, поэтому я бы сказал, что версия цикла while ( bit.ly/2j2mhyb ), пожалуй, лучше. – xn. 11 January 2017 в 00:40
  • 5
    Кстати, вы можете избежать неприятной подстановки {}, если вы позволите xargs добавить аргумент, а затем ссылаться на $1 внутри сценария оболочки, e. g .: xargs -0 -n1 -- bash -c 'dir=/dest/$(basename "$1" | ...); ...; mv "$1" "$dir"' _. (Обратите внимание на окончательный _!) – David Foerster 11 January 2017 в 00:45

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

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