Что является установкой в ударе для globbing, чтобы управлять, соответствует ли * точечным файлам

Обычно история команд сохраняется к скрытому файлу в корневом каталоге пользователя. Кроме этого, можно зарегистрироваться к stderr или системному журналу.

12
13.06.2012, 20:14
5 ответов

Bash

Поскольку Вы уже заметили, что удар не будет соответствовать a . в начале имени или наклонной черты. Для изменения соответствия относительно точки, необходимо установить dotglob опция - удар человека:

dotglob If set, bash includes filenames beginning with a `.'  in
    the results of pathname expansion.

Позволять/устанавливать его с использованием удара shopt, например:

shopt -s dotglob


Для zsh можно также использовать dotglob опция, но но необходимо будет использовать setopt включить его, например:

setopt dotglob
14
27.01.2020, 19:54
  • 1
    С zsh, более оптимальный вариант состоит в том, чтобы включить dotglob на основе на шарик: mv test/*(D) /dest –  Stéphane Chazelas 27.04.2016, 14:28

Я протестировал это, и это решает проблему:

shopt -s dotglob

Вывод:

~/stackexchangeanswers/40662$ ls -hal dest
total 8.0K
drwxr-xr-x 2 jodiec jodiec 4.0K 2012-06-12 22:15 .
drwxr-xr-x 4 jodiec jodiec 4.0K 2012-06-12 22:15 ..
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 1
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 .1
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 2
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 .2
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 3
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 .3
...snipped....
7
27.01.2020, 19:54
  • 1
    Извините, но Ulrich ответил сначала. –  iconoclast 13.06.2012, 06:44
  • 2
    , Мы - все в той же команде. Это в порядке. –  Jodie C 13.06.2012, 07:46

Самый простой способ в bash печатать файлы с совпадающими точками, игнорируя . и .. is:

$ GLOBIGNORE=/+/
$ printf '%s\n' *


Чтобы проверить:

$ cd tmp; mkdir empty; cd empty; touch {,.}{a..h}
$ GLOBIGNORE=/+/
$  ls *
a  .a  b  .b  c  .c  d  .d  e  .e  f  .f  g  .g  h  .h

Он напечатал все файлы с точками или без них, за заметным исключением . и .. .

Ваш пример также будет работать правильно:

$ cd /tmp; mkdir {t,d}est; touch test/{,.}{a..h}
$ mv test/* dest/
$ ls -a test
.  ..
$ ls -a test/*
ls: cannot access test/*: No such file or directory

Пусто от важных файлов.
Системные файлы . .. все еще существуют, но расширение оболочки (с использованием *) не будет включать их.

И каталог dest ination содержит все файлы:

$ cd dest
$ ls -a *
a  .a  b  .b  c  .c  d  .d  e  .e  f  .f  g  .g  h  .h

Почему?

Это работает, потому что установка GLOBIGNORE имеет следующие эффекты стороны :

  • Set dotglob ( shopt -s dotglob ) к файлам математических точек в расширениях.
  • Имена файлов . и .. игнорируются, если GLOBIGNORE установлен, а не null.

Подробности в руководстве: LESS = + '/ The GLOBIGNORE' man bash .

Кроме того, нам нужно установить переменную GLOBIGNORE, чтобы она содержала имя, с которым не может совпадать ни одно имя файла:
косую черту (и что-то еще в качестве двойной меры предосторожности).

$ GLOBIGNORE=/+/

Также может быть полезно установить nullglob, если это необходимо, чтобы избежать получения * , когда нет файла, соответствующего * .

4
28.07.2021, 14:38

* - это глобус, который расширяется оболочкой. По умолчанию shell не включает файлы, имя которых начинается с . (называемые скрытыми файлами или dotfiles), если только ведущее . вводится буквально.

* или [.]* или ?* или *.* или dir/* не будет включать dotfiles.

.* или dir/.* будут.

Так что вы могли бы сделать:

mv -- * .* /dest/

однако некоторые оболочки, включая bash (но не zsh, mksh или fish) имеют ту ошибку, что расширение .* включает . и . специальные записи каталога, которые здесь не нужны (и вообще никогда не нужны, чтобы glob включал их, поэтому я и называю это ошибкой).

По этой причине иногда люди используют (в Bourne-подобных оболочках):

mv -- * .[!.]* ..?* /dest/

Это три глобы, первая из которых соответствует не скрытым файлам, вторая - именам файлов, начинающимся с . , за которым следует символ, отличный от . и третий - имена файлов, начинающиеся с ... , за которым следует хотя бы один символ.

Однако некоторые современные оболочки имеют лучшие способы обойти это

zsh

С zsh вы можете использовать (D) квалификатор glob, чтобы указать, что glob должен включать dotfiles:

mv -- *(D) /dest/

zsh также исправил другую ошибку оболочки Bourne, которая заключается в том, что если шаблон не совпадает, команда mv не выполняется.

Как было сказано выше, она также никогда не будет включать . или ... в свои глобусы, поэтому

mv -- * .* /dest/

будет в безопасности. Однако если нет файла, соответствующего * или файла, соответствующего . * команда будет прервана, поэтому лучше использовать:

mv -- (*|.*) /dest/

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

setopt dotglob

or:

set -o dotglob

После этого, если вы хотите, чтобы конкретный glob not включал dotfiles, вы можете написать:

echo *(^D)

Or:

echo [^.]*

Bash

К сожалению, bash не имеет квалификаторов glob. Поэтому вам остается включить включение dotfile глобально. В bash синтаксис следующий:

shopt -s dotglob

(и используйте [^.]* для глобов без скрытых файлов).

С dotglob, bash не включает . ни ... в глобусах типа *, но все же включает глобусы типа .*.

Если установить переменную GLOBIGNORE в непустое значение, то автоматически включается опция dotglob и исключается . и ... из .* глобов, но не из dir/.* или .*/file (!), так что эта мера предосторожности довольно бесполезна. Вы можете сделать GLOBIGNORE='*/.:*/...:./*:.../*:*/./*:*/.../*', но тогда это нарушит глобы типа */. или ./* или ../*.

Лучшее решение - использовать [.]* или dir/[.]* или [.]*/file (с включенным dotglob) для расширения dotfiles, кроме . и ... .

fish

fish глобы не включают . ни ... . Когда нет совпадений, в зависимости от версии, это будет работать как zsh (или bash -o failglob) или bash -o nullglob.

mv -- * .* /dest/

Будет работать, если есть как скрытые, так и не скрытые файлы. В противном случае, YMMV и в некоторых версиях может вызвать mv -- /dest, если файла вообще нет.

ksh93

В ksh93 также нет квалификатора glob. Вы можете включать dotfiles в globs с помощью:

FIGNORE='@(.|..)'

Вопреки bash в GLOBIGNORE, это делается правильно и также устраняет проблему .*, включающую . и . .

yash

yash имеет опцию dot-glob (set -o dot-glob), но, в отличие от bash, расширения glob (даже из *) включают . и . , так что это довольно бесполезно.

tcsh

set globdot

Работает как в bash, то есть * включает точечные файлы, кроме . и ... , но * по-прежнему включает . и . (и вы можете использовать [.]* для расширения скрытых файлов, кроме . и . ).

9
20.08.2021, 13:25

Очень заинтересовал этот параметр GLOBIGNORE = / + / @ user79743

По моему опыту отключение dotglob - это плохой бизнес почти для всех ваших команд (cp, mv и т. Д.), НО то же самое верно , устанавливая nullglob (особенно с регулярными выражениями, которые затем нужно экранировать!).

Тем не менее, если вам все же нужно установить их в начале программы, но мешает работе определенных частей, где вы вызываете такие команды, как cp, mv и т. Д., Или используете регулярные выражения, просто сделайте следующее:

  # set dotglob, unset nullglob AFTER this
  is_nullglob=$( shopt -s | egrep -i '.*nullglob' )
  is_dotglob=$( shopt -s | egrep -i '.*dotglob' )
  [[ $is_nullglob ]] && shopt -u nullglob
  [[ ! $is_dotglob ]] && shopt -s dotglob
  # ... call commands ...
  # .....................
  # reset dotglob, nullglob to their previous values
  [[ $is_nullglob ]] && shopt -s nullglob
  [[ ! $is_dotglob ]] && shopt -u dotglob
0
20.08.2021, 13:25

Теги

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