![Извлечь все имена файлов с указанным количеством символов](https://rvso.com/image/109243/%D0%98%D0%B7%D0%B2%D0%BB%D0%B5%D1%87%D1%8C%20%D0%B2%D1%81%D0%B5%20%D0%B8%D0%BC%D0%B5%D0%BD%D0%B0%20%D1%84%D0%B0%D0%B9%D0%BB%D0%BE%D0%B2%20%D1%81%20%D1%83%D0%BA%D0%B0%D0%B7%D0%B0%D0%BD%D0%BD%D1%8B%D0%BC%20%D0%BA%D0%BE%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%BE%D0%BC%20%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%BE%D0%B2.png)
Я хочу изменить все имена файлов, они имеют точную длину 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]*
Это потому что
- Шаблоны подстановки не поддерживают модификаторы, которые говорят «повторить предыдущее N раз».
- Шаблоны подстановки по умолчанию привязаны к началу и концу. Вот почему я вставил
*
в начало и конец шаблона. 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
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"
' {} {} \;