Câu trả lời:
Tuyên bố miễn trừ trách nhiệm: Câu trả lời này liên quan đến Bash cụ thể nhưng phần lớn câu hỏi áp dụng cho câu hỏi liên quan đến các mẫu toàn cầu!
Nhân vật ngôi sao ( *
) là một ký tự đại diện. Có một tập hợp các ký tự nhất định sẽ thay thế và ký tự đầu tiên là dấu chấm ( .
) không phải là một trong số chúng. Đây là trường hợp đặc biệt chỉ vì cách các hệ thống tệp Unix hoạt động, các tệp bắt đầu bằng dấu chấm được coi là "ẩn". Điều đó có nghĩa rằng các công cụ như cp
, ls
, vv sẽ không "nhìn thấy" họ trừ khi nói một cách rõ ràng để làm như vậy.
Trước tiên hãy tạo một số dữ liệu mẫu.
$ mkdir .dotdir{1,2} regdir{1,2}
$ touch .dotfile{1,2} regfile{1..3}
Vì vậy, bây giờ chúng ta có những điều sau đây:
$ tree -a
.
|-- .dotdir1
|-- .dotdir2
|-- .dotfile1
|-- .dotfile2
|-- regdir1
|-- regdir2
|-- regfile1
|-- regfile2
`-- regfile3
Bây giờ hãy chơi một số trò chơi. Bạn có thể sử dụng lệnh echo
để liệt kê một ký tự đại diện cụ thể ( *
) sẽ là gì đối với một lệnh đã cho như vậy:
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3
$ echo reg*
regdir1 regdir2 regfile1 regfile2 regfile3
$ echo .*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2
$ echo .* *
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
$ echo .dotdir*
.dotdir1 .dotdir2
Bạn có thể sử dụng lệnh shopt -s dotglob
để thay đổi hành vi của *
nó để ngoài các tệp như regfile1
nó cũng sẽ khớp .dotfile1
.
đoạn trích từ bash
trang người đàn ông
dotglob If set, bash includes filenames beginning with a `.' in the results
of pathname expansion.
Thí dụ:
$ shopt -s dotglob
$ echo *
.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
Bạn có thể hoàn nguyên hành vi này bằng lệnh này:
$ shopt -u dotglob
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3
Đối với bạn, bạn đang nói cp
rằng bạn muốn sao chép tất cả các tệp phù hợp với mẫu *
và không có bất kỳ tệp nào.
$ cp foo/.* .
Hoặc bạn có thể làm điều này nếu bạn muốn mọi thứ trong foo
thư mục:
$ cp foo .
Hoặc bạn có thể rõ ràng:
$ cp foot/.* foo/* .
Một hình thức nhỏ gọn hơn bằng cách sử dụng mở rộng nẹp trong bash
:
$ cp foo/{.,}* .
Bất cứ lúc nào bạn cũng có thể sử dụng echo
thủ thuật để xem các mẫu tệp được đề xuất của bạn (đó là thuật ngữ ưa thích cho những gì ngôi sao là một phần của).
$ echo {.,}*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 abc regdir1 regdir2 regfile1 regfile2 regfile3
Ngẫu nhiên nếu bạn định sao chép một thư mục tệp + thư mục khác, bạn thường muốn thực hiện việc này một cách đệ quy, đó là -R
chuyển sang cp
:
$ cp -R foo/. .
shopt -s dotglob
, echo *
sau đó đưa ra:.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
cp -r foo .
thông thường sẽ không hoạt động vì cp
sẽ từ chối sao chép foo
chính nó, có lẽ bạn có nghĩa là cp -R foo/. .
. (lưu ý đó cp -R
là tiêu chuẩn).
zsh
không bao gồm .
và ..
trong việc mở rộng .*
. Trong zsh
, nếu một mẫu không khớp, lệnh sẽ bị hủy bỏ (khá hợp lý trở lại), vì vậy trong trường hợp chung, cp foo/{,.}* .
sẽ thất bại nếu không có tệp ẩn hoặc không có tệp không bị ẩn.
shopt
không tồn tại.
Với zsh
, cách điển hình là sử dụng D
vòng loại toàn cầu (bao gồm các tệp ot [D]):
cp foo/*(D) .
Lưu ý rằng có hoặc không có D
, các khối zsh không bao giờ bao gồm .
cũng không ..
(như bạn mong đợi).
Nếu những gì bạn muốn làm là sao chép tất cả các tệp và thư mục từ nơi này sang nơi khác, bạn có thể sử dụng rsync
lệnh tiêu chuẩn . Trong ví dụ bạn đưa ra ở trên:
mkdir foo && touch foo/.test
rsync -a foo/ .
sẽ sao chép đệ quy tất cả các nội dung của foo
, bao gồm các tệp ẩn và thư mục ẩn, vào thư mục hiện tại. Dấu gạch chéo ở cuối foo/
là rất quan trọng đối với rsync; với nó chỉ có nội dung foo
được sao chép, mà không có nó rsync cũng sẽ sao chép foo
. Ví dụ:-
mkdir src && mkdir dest && touch src/.test
rsync -a src dest // copies 'src' contents to 'dest/src'
rsync -a src/ dest // copies 'src' contents to 'dest'
Có nhiều tùy chọn khác có sẵn tinh chỉnh rsync, bao gồm sao chép giữa các máy.
Câu trả lời zsh của Stéphane Chazelas là chính xác cho một biểu thức duy nhất có một hình cầu trong đó. Tuy nhiên, nếu bạn muốn đặt nó cho tất cả các biểu thức theo mặc định, bạn có thể sử dụng
setopt GLOB_DOTS
Đặt nó trong của bạn ~/.zshrc
để làm cho nó vĩnh viễn.
dotglob
được phiên dịch sangglobdots
bởi zsh đó là tên tùy chọn không hợp lệ cho bash .