Извлечь все имена файлов с указанным количеством символов

Извлечь все имена файлов с указанным количеством символов

Я хочу изменить все имена файлов, они имеют точную длину 16 символов (цифры и строчные буквы). Я пробовал [0-9a-z]{16}и [0-9a-z]\{16\}для заполнителя regXв следующем фрагменте, но это не работает.

for file in <regX>
do
  mv "$file" "${file}.txt"
done

решение1

Модели подстановки оболочекне являются регулярными выражениями. Они могут выглядеть одинаково, но в некоторых отношениях работают совершенно по-разному.

Регулярное выражение [0-9a-z]{16}сопоставляет строку, содержащую последовательность из 16 символов указанного диапазона (строка, содержащая совпадение, может быть длиннее).

Эквивалентный шаблон подстановки оболочки будет выглядеть примерно так:

*[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]*

Это потому что

  1. Шаблоны подстановки не поддерживают модификаторы, которые говорят «повторить предыдущее N раз».
  2. Шаблоны подстановки по умолчанию привязаны к началу и концу. Вот почему я вставил *в начало и конец шаблона. A *соответствует любому количеству любых символов. Удалите их, если хотите соответствоватьточно16 символов.

Вы можете создать строку из 16 символов [0-9a-z]с помощью Perl:

$ pattern="$( perl -e 'print "[0-9a-z]" x 16' )"

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

for name in *; do
    if [[ -f "$name" ]] && [[ "$name" =~ ^[0-9a-z]{16}$ ]]; then
        echo mv "$name" "$name.txt"
    fi
done

Удалите его, echoкак только убедитесь, что он работает правильно.

Обратите внимание, что я закрепил шаблон, так что более длинные имена не будут совпадать. Я также убеждаюсь, с помощью теста -f, что имена, которые мы получаем, на самом деле являются именами только обычных файлов.

решение2

Сextglob

shopt -s extglob
for file in +([0-9a-z])
do
    [[ ${#file} == 16 ]] && echo mv "$file" "${file}.txt"
done
  • +([0-9a-z])означает один или несколько [0-9a-z]символов
  • ${#file}дает длину имени файла
  • echoпредназначен для пробного запуска, удалите, когда все будет хорошо

решение3

Если у вас есть perl-rename (вызывается renameв системах на базе Debian perl-renameи других), вы можете сделать следующее:

perl-rename -n 's/^[0-9a-z]{16}$/$&.txt/' *

Если это то, что вам нужно, удалите , -nчтобы он действительно переименовал файлы. Синтаксис perl-rename— это команда perl. Здесь мы используем оператор подстановки ( s/from/to/), который заменит fromна to. fromВ данном случае — это ваше регулярное выражение, а — toэто специальная переменная $&, которая означает «все, что совпало», плюс расширение .txt.


Чтобы сделать это с помощью оболочки (используйте@Кусалананда'sили@Sundeep'sподход, это просто для полноты картины):

for f in [0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]; do
    mv -- "$f" "$f".txt
done

С GNU find:

find . -regextype posix-extended -regex '.*/[0-9a-z]{16}' -exec mv {} {}".txt" \;

решение4

L16=$(csh -c 'repeat 16 echo -n "?"')
find . -name "$L16" ! -name '*[!0-9a-z]*' -exec sh -c '
   mv "$1" "$1.txt"
' {} {} \;

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