Wzorzec nazwy pliku powłoki, który rozwija się do plików kropkowych, ale nie do „..”?


13

Niedawno miałem mały błąd spowodowany przez wzór powłoki, który rozszerzył się w nieoczekiwany sposób. Chciałem zmienić właściciela pliku kropek w /rootkatalogu, więc zrobiłem to

chown -R root .*

Oczywiście .*rozszerzony, do ..którego była trochę katastrofa.

Wiem, że w bashtym zachowaniu można zmienić poprawiając niektóre opcje powłoki, ale czy przy ustawieniach domyślnych jest jakiś wzorzec, który rozwijałby się do każdego pliku kropki w katalogu, ale nie do .i ..?

Odpowiedzi:


20

Bash, ksh i zsh mają lepsze rozwiązania, ale w tej odpowiedzi zakładam powłokę POSIX.

Wzór .[!.]*pasuje do wszystkich plików, które zaczynają się od kropki, po której następuje znak bez kropki. (Należy pamiętać, że [^.]jest obsługiwany przez niektóre powłoki, ale nie wszystkie, przenośna składnia uzupełniania zestawu znaków we wzorach wieloznacznych to [!.].) Dlatego wyklucza .i .., ale także pliki, które zaczynają się od dwóch kropek. Wzór ..?*obsługuje pliki, które zaczynają się od dwóch kropek i nie są po prostu ...

chown -R root .[!.]* ..?*

Oto klasyczny wzorzec, który pasuje do wszystkich plików:

* .[!.]* ..?*

Ograniczeniem tego podejścia jest to, że jeśli jeden ze wzorów nic nie pasuje, jest przekazywany do polecenia. W skrypcie, gdy chcesz dopasować wszystkie pliki w katalogu z wyjątkiem .i ..istnieje kilka rozwiązań, wszystkie z nich kłopotliwe:

  • Zastosowanie * .*wyliczyć wszystkie wpisy, i uwzględniają .i ..w pętli. Jeden lub oba wzorce mogą się nie zgadzać, więc pętla musi sprawdzić istnienie każdego pliku. Masz możliwość filtrowania według innych kryteriów; na przykład usuń -htest, jeśli chcesz pominąć wiszące dowiązania symboliczne.

    for x in * .*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • Bardziej złożony wariant, w którym polecenie jest uruchamiane tylko raz. Zauważ, że parametry pozycyjne są spłaszczone (powłoki POSIX nie mają tablic); umieść to w osobnej funkcji, jeśli jest to problem.

    set --
    for x in * .[!.]* ..?*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      set -- "$@" "$x"
    done
    somecommand "$@"
  • Użyj * .[!.]* ..?*tryptyku. Ponownie jeden lub więcej wzorów może się nie zgadzać, więc musimy sprawdzić istniejące pliki (w tym wiszące dowiązania symboliczne).

    for x in * .[!.]* ..?*; do
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • Użyj * .[!.]* ..?*tryptyku i uruchom polecenie raz na wzór, ale tylko jeśli coś pasuje. Uruchamia to polecenie tylko raz. Zauważ, że parametry pozycyjne są spłaszczone (powłoki POSIX nie mają tablic), jeśli jest to problem, umieść to w osobnej funkcji.

    set -- *
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- .[!.]* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- ..?* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    somecommand "$@"
  • Zastosowanie find. Z GNU lub BSD find, unikanie rekurencji jest łatwe dzięki opcjom -mindepthi -maxdepth. Z POSIX find jest to trochę trudniejsze, ale można to zrobić. Zaletą tego formularza jest łatwe uruchamianie polecenia jednorazowo zamiast raz na plik (ale nie jest to gwarantowane: jeśli wynikowe polecenie jest zbyt długie, polecenie będzie uruchamiane w kilku partiach).

    find . -name . -o -exec somecommand {} + -o -type d -prune

6

Działa to, jeśli wszystkie nazwy plików zawierają co najmniej trzy znaki (w tym kropkę):

chown -R root .??*

Aby uzyskać bardziej niezawodne rozwiązanie, możesz użyć find:

find . -maxdepth 1 -name '.*' -exec chown -R root {} \;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.