* İşaretlerinin nokta dosyalarıyla eşleşip eşleşmediğini kontrol etmek için globbing için bash'daki ayar nedir?


12

Son zamanlarda böyle bir şey yaptığımda şaşırdım mv ./* ../somedirectory ve böyle dosyaların .gitignoretaşınmadığını gördüm .

İşlerimin çoğunu OS X'te zsh'de yapıyorum ve bu sürpriz beni CentOS'ta bash'de ısırdı. OS X'te bash'ı denedim ve aynı davranışı buldum: *nokta dosyalarıyla eşleşmiyor. Bu benim için çok istenmeyen görünüyor, ama görünüşe göre bu bash varsayılanı. (Hatırladığım her şey için de zsh varsayılanı olabilir, ancak yıllar önce .zshrc'de değiştirmiş ve farklı çalıştığını unutmuş olabilirim.)

Bash'ı beklediğim gibi davranacak şekilde nasıl yapılandırabilirim: * için tüm dosyaları eşleştirmek ve nokta dosyalarını yok saymamak.

Bunun net olmadığı durumda, nasıl yeniden üretileceği

cd /tmp
mkdir {t,d}est
touch test/{.,}{1,2,3,4,5,6,7}
ls -hal test
mv test/* dest
ls -hal test     # notice dot files are still there
ls -hal dest     # notice only some files were mv'ed


Evet, ilgililer. Bu arama yaptığımda ortaya çıkmadı (muhtemelen sorgulayanın globbing veya dot dosyalarından bahsetmediği için), ama gerçekten farklı bir soru. Dosyaların nasıl taşınacağını soruyordu ve ben de kabuk davranışını nasıl değiştireceğini ve özellikle bash için soruyordum. Bu sorunun benim için görünüp görünmediğini sormamış olabilirim (son derece eksiksiz ve kapsamlı cevabınız bash ayarını içerdiğinden), ancak yine de farklı bir soru ve soruma cevap arayan biri mutlaka bulamayacak sorusu.
iconoclast

Tüm "soruma cevap arayan biri mutlaka onun sorusunu bulamayacak" işi, tam da bu yüzden soruları kopya olarak bu şekilde kapatmamızın nedenidir.
Gilles 'SO- kötü olmayı bırak

evet, ama ana noktayı kaçırıyor görünüyorsunuz, bu farklı bir soru .
iconoclast

Yanıtlar:


14

darbe

Daha önce fark ettiğiniz gibi, bash .adın başındaki veya eğik çizginin başındaki a ile eşleşmez . Nokta ile ilgili eşleşmeyi değiştirmek için dotglobseçeneği ayarlamanız gerekir - man bash :

dotglob Ayarlanmışsa, bash `` '' ile başlayan dosya adlarını içerir. içinde
    yol adı genişletmesinin sonuçları.

Bash ile etkinleştirmek / ayarlamak için shopt, örneğin:

shopt -s dotglob


Zsh için dotglobseçeneği de kullanabilirsiniz, ancak setoptetkinleştirmek için kullanmanız gerekir, örneğin:

setopt dotglob

2
İle zshdaha iyi bir seçenek dotglob'u glob bazında etkinleştirmektir :mv test/*(D) /dest
Stéphane Chazelas

7

Bunu test ettim ve sorunu çözdü:

shopt -s dotglob

Çıktı:

~/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....

Üzgünüm ama Ulrich önce cevap verdi.
iconoclast

3
Hepimiz aynı takımdayız. Tamam.
Jodie C

6

*kabuk tarafından genişletilen bir küredir. Varsayılan olarak mermiler ., önde gelmedikçe adı bir ile başlayan dosyaları (gizli dosyalar veya dotfiles olarak adlandırılır) içermez. tam olarak girilmedikçe .

*veya [.]*veya ?*veya *.*veya dir/*nokta dosyaları içermeyecektir.

.*ya da dir/.*olacak.

Böylece şunları yapabilirsiniz:

mv -- * .* /dest/

Ancak dahil olmak üzere bazı kabukları bash(ancak zsh, mkshne de fishgenişlemesi olduğunu) o misfeature var .*içerir .ve ..size (Ben bir misfeature diyoruz neden olan içerecek bir topak istiyorum ve genellikle hiç) burada istemiyoruz özel dizin girişlerini.

Bu nedenle, bazen insanların (Bourne benzeri kabuklarda) kullandığını göreceksiniz:

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

Bu üç glob, ilki gizli olmayan dosyalarla eşleşiyor, ikincisi dosya adları ile başlayan ve .ardından başka bir karakter. ve 3. biriyle başlayan dosyalardan ..sonra en az bir karakter.

Ancak bazı modern mermilerin daha iyi yolları var

zsh

İle zsh, (D)glob'un dotfiles içermesi gerektiğini belirtmek için glob niteleyicisini kullanabilirsiniz :

mv -- *(D) /dest/

zsh ayrıca Bourne kabuğunun diğer yanlış özelliklerinin, eğer desen eşleşmezse, mv komutun çalıştırılmayacağı .

Yukarıda belirtildiği gibi, asla kürelerini .de içermez .., bu yüzden

mv -- * .* /dest/

güvenli olacak. Bununla birlikte, eşleşen bir dosya *yoksa veya .*komutla eşleşen hiçbir dosya iptal edilirse, bu nedenle kullanmak daha iyi olur:

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

Diğer bazı kabuklarda olduğu gibi, tüm glob'ları dotfiles eklemeye zorlayabilirsiniz (örneğin kendinizi dotfiles'i daha sık dahil etmek istemiyorsanız):

setopt dotglob

veya:

set -o dotglob

Belirli bir topak istiyorsanız Bundan sonra değil dotfiles dahil etmek, bunu yazabiliriz:

echo *(^D)

Veya:

echo [^.]*

darbe

Ne yazık ki bashglob elemeleri yok. Böylece global olarak dotfile dahil etmeyi etkinleştirebilirsiniz. İçinde bashsözdizimi:

shopt -s dotglob

(ve [^.]*gizli dosyaları olmayan globlar için kullanın ).

İle dotglob, bashiçermez .ne de ..benzeri Neználkovo içinde *, ama yine de böyle Neználkovo için yaptığı .*.

Eğer ayarlarsanız GLOBIGNOREşey boş olmayan değişkeni, daha sonra otomatik olarak sağlayan dotglobseçeneği ve Kapsam dışı .ve ..gelen .*Neználkovo ancak gelen dir/.*veya .*/fileolanları (!) O koruma oldukça işe yaramaz böylece. Yapabilirsin GLOBIGNORE='*/.:*/..:./*:../*:*/./*:*/../*'ama sonra globları kırabilir */.ya da./* ya ../*.

Daha iyi bir iş etrafında kullanmaktır [.]*ya dir/[.]*ya [.]*/file(ile dotglobhariç dotfiles genişletmek için etkin) .ve.. .

balık

fishNeználkovo içermez .ne de ... Sürüm eşleşmediğinde, sürüme bağlı olarak, zsh(veya bash -o failglob) veya gibi çalışır bash -o nullglob.

mv -- * .* /dest/

Hem gizli hem de gizli olmayan dosyalar varsa çalışır. Aksi takdirde, YMMV ve bazı sürümlerde,mv -- /dest hiç dosya yoksa .

ksh93

Hiçbir glob niteleyici de ksh93. Glob'lara nokta dosyaları aşağıdakileri ekleyebilirsiniz:

FIGNORE='@(.|..)'

Aksine bash'ın GLOBIGNOREda düzgün yapılmazsa ve oluyor, sorununu giderir .*dahil .ve ...

yash

yashbir dot-globseçenek ( set -o dot-glob) vardır, ancak aksine bash, glob genişletmeleri (hatta *) içerir .ve ..bu yüzden oldukça işe yaramaz.

tcsh

set globdot

Gibi İşleri bash, yani *hariç nokta dosyaları içerir .ve ..ancak .*hala içerir .ve ..(ve kullanabileceğiniz [.]*hariç gizli dosyaları genişletmek .ve ..).


4

Bash'da eşleşen nokta dosyalarını yazdırmanın en kolay yolu, yok saymak .ve ..:

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


Test etmek için:

$ 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

Bu dikkate değer hariç, nokta veya değil tüm dosyaları baskılı .ve ...

Örneğiniz de düzgün çalışacaktır:

$ 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

Önemli dosyalar boş.
Sistem dosyaları. .. hala var, ancak kabuk genişletme (* kullanarak) bunları içermeyecek.

Ve dest ination dizini tüm dosyaları içerir:

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

Neden?

GLOBIGNORE ayarının şu yan etkileri olduğu için çalışır:

  • Dotglob ( shopt -s dotglob) öğesini genişletmelerdeki matematik nokta dosyalarına ayarlayın .
  • Dosya adları . ve ..GLOBIGNORE ayarlandığında boş bırakılmaz.

Kılavuzdaki detaylar: LESS=+'/The GLOBIGNORE' man bash .

Ayrıca, GLOBIGNORE değişkenini hiçbir dosya adının eşleşemeyeceği bir ad içerecek şekilde ayarlamamız gerekir:
bir eğik çizgi (ve sadece bir çift önlem olarak başka bir şey).

$ GLOBIGNORE=/+/

Eşleşecek bir *dosya olmadığında bir almayı önlemek gerekiyorsa nullglob ayarlamak da yararlı olabilir *.


0

Bu GLOBIGNORE ayarıyla çok ilgiliyim = / + / @ user79743

Benim deneyim unsetting dotglob olan kötü iş neredeyse tüm komutları (cp, mv vb) AMA aynı doğrudur ayarı nullglob (özellikle o kaçan gerek düzenli ifadeler ile!).

Bununla birlikte, bunları programınızın başlangıcında ayarlamanız gerekiyorsa, ancak cp, mv vb. Gibi komutları çağırdığınız veya düzenli ifadeleri kullandığınız belirli bölümlere müdahale ediyorsanız şunları yapın:

  # 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.