найти только те файлы, которые заканчиваются на .whl

Я пытаюсь захватить все файлы .whlкак следующее

ls -l  /python/*.{whl,}
ls: cannot access /python/*.: No such file or directory
-rw-r--r-- 1 root root   23000 Jun 14 11:02 /python/argparse-1.4.0-py2.py3-none-any.whl
-rw-r--r-- 1 root root  154423 Jun 14 11:02 /python/certifi-2019.9.11-py2.py3-none-any.whl
-rw-r--r-- 1 root root  387834 Jun 14 11:02 /python/cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl
-rw-r--r-- 1 root root  133356 Jun 14 11:02 /python/chardet-3.0.4-py2.py3-none-any.whl
-rw-r--r-- 1 root root 2728298 Jun 14 11:02 /python/cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl
-rw-r--r-- 1 root root   11223 Jun 14 11:02 /python/enum34-1.1.10-py2-none-any.whl
-rw-r--r-- 1 root root   58594 Jun 14 11:02 /python/idna-2.8-py2.py3-none-any.whl
-rw-r--r-- 1 root root   18159 Jun 14 11:02 /python/ipaddress-1.0.23-py2.py3-none-any.whl
-rw-r--r-- 1 root root  125774 Jun 14 11:02 /python/Jinja2-2.11.2-py2.py3-none-any.whl

, но, как вы можете видеть, мы также получаем - ls: невозможно получить доступ к /python/*.: Нет такого файла или каталога

, как это исправить, чтобы найти только файлы, оканчивающиеся на . вл

0
24.06.2020, 05:32
2 ответа

Если вас интересуют только файлы с расширением whl,

ls -l /python/*.whl

— это то, что вам нужно.

Ваша текущая команда,

ls -l  /python/*.{whl,}

эквивалентно

ls -l /python/*.whl /python/*.

(благодаря раскрытию фигурных скобок )и терпит неудачу, потому что последний шаблон ничему не соответствует в /python.

10
18.03.2021, 23:25

Как сказал @StephenKitt, сказал, что в bashрасширение скобок выполняется перед подстановкой (даже перед всеми другими формами расширения, включая раскрытие параметров, см., как bashявляется единственной оболочкой где echo $P{S1,ATH}выводит содержимое как $PS1, так и $PATH), поэтому

ls -l /python/*.{whl,}

совпадает с:

ls -l /python/*.whl /python/*.

И bashимеет эту неверную функцию, унаследованную от оболочки Bourne, которая не совпадает с подстановочными значениями, которые передаются команде буквально, поэтому, если в /pythonнет не -скрытого файла, имя которого заканчивается на ., имя файла /python/*.будет передано ls, а lsжалуется, что этот файл (да, *.является вполне допустимым именем файла в Unix )не существует. Обратите внимание, что опции failglobи nullglobизменяют это поведение.

Теперь функция расширения фигурных скобок пришла из csh в конце 70-х. И вы заметите, что вы не видите эту ошибку в csh.

cshне имеет этой неправильной функции оболочки Bourne и ведет себя как /etc/globранних Unices (, которые дали свое имя глобусам )в том, что глобы, которые не совпадают, удаляются (вместо передается как -равно ), и если все глобусы в командной строке не совпадают,затем команда отменяется (разумный поступок, так как явно что-то не так ).

Итак, вcsh:

ls -l /python/*.{whl,}

сначала расширяется до

ls -l /python/*.whl /python/*.

аналогично bash, но поскольку /python/*.не соответствует ни одному файлу, а /python/*.whlсоответствует некоторым файлам, /python/*.удаляется, а lsвызывается со списком .whlфайлов.

Если бы не было никакого .whlфайла, у вас была бы No matchошибка от csh , вместо ошибки отlsо не -существующие файлы.

zsh— еще одна оболочка, которая скопировала раскрытие фигурных скобок из csh. Поведение непревзойденных глобусов отличается.

zshне имеет этого недостатка оболочки Bourne (, по крайней мере, не по умолчанию ), но отменяет команды до тех пор, пока любые(в отличие от все в csh//etc/glob)glob не соответствует, поэтому ls -l /python/*.{whl,}или ls -l /python/*.whl /python/*.не будет запускать ls, даже если есть .whlфайлы, потому что /python/*.glob не совпадает. В zshвы можете получить поведение cshвместо set -o cshnullglobили поведение Борна сset +o nomatch(не рекомендуется ). В bashвы можете получить поведение, подобное zsh, с помощью shopt -s failglob.

Поведение оболочки fishотличается.

fish(гораздо более новая оболочка )ведет себя как zshв том, что сбойные глобусы отменяют команду. Как и в zsh, вы увидите, что

ls -l /python/*.whl /python/*.

не запускается lsи возвращает:

fish: No matches for wildcard “/python/*.”. See `help expand`.
ls -l /python/*.whl /python/*.
                    ^

ошибка. Но

ls -l /python/*.{whl,}

возвращает ли не ошибку, перечисляет файлы .whlи передает ли не аргумент /python/*.в lsв этом случае как csh.

Но это потому, что хотя {x,y}и здесь не является, строго говоря, подстановочным оператором, он выполняется наряду с подстановкой, и только если подстановка, выполненная для всей фигурной скобки, не соответствует ни одному файлу, является команда отменена.Вы увидите, что если нет ни файлов *.whl, ни *., ошибка становится:

fish: No matches for wildcard “/python/*.{whl,}”. See `help expand`.
ls -l /python/*.{whl,}
      ^

То есть весь /python/*.{whl,}считается подстановочным знаком здесь, а не подстановочным знаком, полученным в результате раскрытия фигурной скобки.

Чтобы перечислить файлы, оканчивающиеся на .whlили ., я бы сделал:

ls -ld /python/*(.|.whl)  # zsh
ls -ld /python/*.(|whl)   # zsh
ls -ld /python/*@(.|.whl) # ksh / bash -O extglob
ls -ld /python/*.?(whl)   # ksh / bash -O extglob

То есть используйте оператор glob внутри одного glob, который соответствует либо, а не двум glob, по одному для каждого случая (, если только вы не хотите, чтобы файлы .whlбыть в списке первым, но в случае lsв качестве команды это не имеет значения, так как lsвсе равно сортирует список ).

Однако имейте в виду, что варианты ksh, если вы не используете failglobв bash, могут привести к тому, что -будет содержать список файлов, буквально именуемых *.?(whl), если не было файла, соответствующего этому шаблону, из-за неправильной функции оболочки Bourne..

в zsh, если вы хотите перечислить файлы *.whlперед *., не рассматривая это как ошибку, если какой-либо список пуст, как в csh/ fish, вы можете использовать cshnullglobлокально:

(){ set -o localoptions -o cshnullglob; ls -ldU /python/*.{whl,}; }

(здесь предполагается GNU lsи используется его опция -Uдля отключения сортировки ).

Или используйте квалификатор Nglob (, чтобы получить nullglobповедение )и выполнить обработку ошибок (для случая, когда ни один glob не соответствует )вручную:

() {
  if (($#)); then
    ls -ldU -- "$@"
  else
    echo>&2 No match
    return 1
  fi
} /python/*.{whl,}

Нечто подобное можно было бы сделать в bash с помощью подоболочки (, поскольку bashне имеет анонимных функций )для ограничения объема опций и позиционных параметров:

(
  shopt -s nullglob
  shopt -u failglob # failglob takes precedence over nullglob when set!
  set -- /python/*.{whl,}
  if (($#)); then
    ls -ldU -- "$@"
  else
    echo>&2 No match
    exit 1
  fi
)
3
18.03.2021, 23:25

Теги

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