Я использую ls
команду в bash, пытаясь найти все файлы или каталоги длины n. Допустим, n=5
Моя команда:
ls ?????
Но это также будет включать символы, которые не являются буквами, такие как точка. Например, следующие файлы будут соответствовать:
ab.cd
abd.c
Мне нужно найти только файлы, имена которых состоят из 5 букв или цифр:
five1
five2
five3
Но нет
abc.d
ab.cd
a.bcd
Как я могу изменить свою команду?
Ответ найден:
ls [a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]
Я нашел ответ, но как сделать это менее уродливым?
решение1
Обратите внимание, что это не ls
то, что интерпретирует эти глобусы. Эти глобусы расширяются вашей оболочкой в список имен файлов, который передается в качестве аргументов в ls
. Разные оболочки имеют разные возможности глобализации. bash
имеет несколько расширений по сравнению со стандартными глобусами (заимствованными из ksh88
и включенными с помощью shopt -s extglob
), но все еще ограничен по сравнению с такими оболочками, как zsh
или ksh93
.
С zsh
:
setopt extendedglob
ls -d [[:alnum:]](#c5)
ksh93
:
ls -d {5}([[:alnum:]])
или:
ls -d {5}(\w) # (\w includes underscore in addition to alnums)
или, если вы хотите использовать расширенные регулярные выражения:
ls -d ~(E)^[[:alnum:]]{5}$
С помощью bash
или других оболочек POSIX, не имеющих эквивалентных операторов подстановки, вам необходимо сделать следующее:
ls -d [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
Обратите внимание, что [[:alnum:]]
сюда входят любые алфавитные символы в текущей локали (не только латинские алфавиты, не говоря уже об английском) и 0123456789
(и, возможно, другие типы цифр). Если вам нужны буквы английского алфавита, назовите символы по отдельности:
c='[0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]'
unset -v IFS
ls -d $c$c$c$c$c
Или используйте локаль C:
(export LC_ALL=C
ls -d [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]])
решение2
ls -q | grep -Ex '[[:alnum:]]{5}'
решение3
Если вы собираетесь использовать ls
указанным вами способом, вам следует использовать опцию -d
; в противном случае будет выведен списоксодержаниелюбойкаталоги
чьи имена состоят из пяти букв и/или цифр, а не перечисление самих имен. Также, вы можете сделать
ls -d [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
но это ровно столько же текста, сколько и ответ, который вы получили сейчас.
Кроме того, если вы этого не сделаете,нуждатьсядля использования ls
в вашей команде, вы можете использовать
echo [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
который выведет список всех совпадений на одной строке, или
printf "%s\n" [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][:alnum:]]
который перечислит их в отдельных строках.
решение4
Постройте выражение в переменной:
e=""; for m in $(seq 1 5); do e="$e[A-Za-z0-9]"; done
Поместите это в функцию, чтобы сделать ее более интересной/многоразовой:
alnumglob() {
local e=""
for m in $(seq 1 $1) ; do e="$e[A-Za-z0-9]"; done
echo "$e"
}
ls -ld $(alnumglob 5)