Hedef belirtmeden `mv ./* 'ne yapar?


27

Yanlışlıkla Dönüş tuşuna basmadan önce varış yerini belirlemeyi unuttum. mv ./*Hedef belirtilmeden, geçerli dizin altındaki dosyaları ve dizinleri nereye taşınır?



4
mv1 argümanı kabul etmesine şaşırdım ” değil. Genişlettikten sonra kabuğun kendisine ilettiği tüm argümanları kabul eder *.
glglgl

Yanıtlar:


41

Son bağımsız değişken bir dizinse, geçerli çalışma dizininizdeki tüm dosyaları ve dizinleri (adları noktalarla başlayanlar hariç) o dizine taşıdınız. İki dosya olsaydı, ilk dosya ikinci dosyanın üzerine yazmış olabilir.

İşte bazı gösteriler:

İkiden fazla dosya ve son argüman bir dosyadır

$ mkdir d1 d2 d3
$ touch a b c e
$ mv *
mv: target 'e' is not a directory

İkiden fazla dosya ve son argüman bir dizindir.

$ mkdir d1 d2 d3
$ touch a b c
$ mv -v *
'a' -> 'd3/a'
'b' -> 'd3/b'
'c' -> 'd3/c'
'd1' -> 'd3/d1'
'd2' -> 'd3/d2'

İki dosya

$ touch a b
$ mv -v *
'a' -> 'b'

Daha fazla açıklama

Kabuk, glob ( *) işlevini argümanlara genişletir mv. Küre genellikle alfabetik sırayla genişletilir. mvher zaman bir dosya ve dizin listesini görür. Glob'un kendisini asla görmez.

Komut mviki tip hareketi destekler. Birincisi mv file ... directory. Diğeri mv old-file-name new-file-name(veya mv old-file-name directory/new-file-name).


30

İlk önce bir test tabanı yapacağım - 5 dosya ve bir klasör:

touch file1 file2 file3 file4 file5
mkdir folder

Sonra bir test komutu çalıştıracağım. -vSeçenek belirtir Ben kabuk yürüttüğü için basılacak her komutu istediğiniz stderr. -xBen basılmış aynı istiyoruz seçenek belirtir stderr- ama yapılmasını isterim sonra komut değerlendirilir ama önce kabuk çalıştırır.

sh -cxv 'echo mv *'

ÇIKTI

echo mv *
+ echo mv file1 file2 file3 file4 file5 folder
mv file1 file2 file3 file4 file5 folder

Yani, kabuğu beslediğim komutu görüyorsunuz echo mv *ve kabuğun genişletildikten sonra yürüttüğü komut tüm bu dosyalar ve klasörler tarafından takip ediliyor.*echo mv

Varsayılan olarak, kabuk aşağıdaki gibi globları genişletir :

sh -cxv 'echo file[1-5]'

ÇIKTI

echo file[1-5]
+ echo file1 file2 file3 file4 file5
file1 file2 file3 file4 file5

Bu, set [+-]fglob işlevinin bir sonucudur :

sh -cxvf 'echo file[1-5]'

ÇIKTI

echo file[1-5]
+ echo 'file[1-5]'
file[1-5]

Bu nedenle mv *, kabuk gibi varsayılan seçeneklerle yapılandırılmış bir kabukta bir komut çalıştırdığınızda , *kelimeye, geçerli dizindeki tüm dosyaların yerel ayarlarına göre sıralanmış bir argüman listesi genişler . Bu sistem çağrısını yapar exec(ve)için mv (aslında) eklenen bu argüman listesi ile. Böylece mvtüm argümanlar kabuk onları götürür ve sıralar gibi alır. Yapıyor yanı sıra stracebu etkileri görmek için, tekrar hata ayıklama gibi dışarı kullanabilirsiniz:

sh -s -- mv * <<\SCRIPT
sed -n l /proc/$$/cmdline
echo "$@"
SCRIPT

ÇIKTI

sh\000-s\000--\000mv\000file1\000file2\000file3\000file4\000file5\000folder\
\000$
mv file1 file2 file3 file4 file5 folder

Ve taşınabilir olarak:

( PS4= IFS=/; set -x mv *; : "/$*/" ) 2>&1

ÇIKTI

: /mv/file1/file2/file3/file4/file5/folder/

Temel olarak, kabuk yürütür mvdizinin içeriği ile (isimler ile başlayan ile dosyaları / klasörleri dahil bu boş değilse, değil .) onun argüman listesi olarak. mvaynı şekilde - POSIX ikiden fazla argümanla çağrılır eğer bir dizin olarak nihai argümanı yorumlamak belirtilen olduğu lnolduğu (aslında, onlar fonksiyonu altında yatan inanılmaz derecede benzer araçlar olduğunuz için) .

Yeterince yeter echo:

sh -cxv 'mv *' ; ls

ÇIKTI

mv *
+ mv file1 file2 file3 file4 file5 folder
folder/

Tüm dosyalar son argümana taşındı - çünkü bu bir klasör. Peki ya klasör değilse?

sh -cxv 'cd *; mv *'; ls . *

ÇIKTI

cd *; mv *
+ cd folder
+ mv file1 file2 file3 file4 file5
mv: target ‘file5’ is not a directory

.:
folder/

folder:
file1  file2  file3  file4  file5

POSIX’in mv bu durumda nasıl davranması gerektiğini şöyle ifade eder:

mv [-if] source_file target_file

mv [-if] source_file... target_dir

İlk özet biçiminde, mvyardımcı program source_file operand tarafından adlandırılan dosyayı target_file tarafından belirtilen hedefe taşıyacaktır . Bu ilk özet formu, son işlenen varolan bir dizine isim vermediğinde ve varolan bir dizine işaret eden sembolik bir bağ olmadığında varsayılır. Bu durumda, source_file dizin dışı bir dosyayı isimlendirir ve target_file izleyen bir /slashkarakterle bitiyorsa , mvbunu bir hata olarak kabul eder ve hiçbir source_file işleneni işlenmez.

İkinci özet formunda, mvsource_file operand adıyla belirtilen her dosyayı target_dir operand tarafından adlandırılan varolan dizindeki bir hedef dosyaya veya hedef_dir'in varolan bir dizine atıfta bulunan sembolik bir bağ olması durumunda başvuruda bulunmalıdır . Her source_file için hedef yolu, hedef dizinin bitiştirilmesi, hedef bir bitmediyse tek bir /slashkarakter /slashve source_file öğesinin son yol adı bileşeni olmalıdır . Bu ikinci form, final operand varolan bir dizini adlandırdığında varsayılır.

Yani *genişlerse:

  • iki dosya

    • Sadece bir dosyaya sahip olmalısınız, ki renamedbu ikinciden sonraki ilk ikinciye aittir unlinked.
  • Bir ya da daha fazla dosyayı izleyen en son bir dizin ya da bir link

    • Sadece bir dizine ya da bir dizine bağlantı vermelisiniz, bu da üst öğesinin tüm içeriğinin yeni taşındığı yer.
  • başka herhangi bir şey

    • Bir hata mesajı ve tatmin edici bir rahatlama hissi vermelisiniz.

1
evet, eski shşeyi kullanarak , bununla hata ayıklamayı unuttum, ama asıl sorumla ilgili olarak, sorunun kabuk olmadığı anlamına mvmı geliyor? Bu iğrenç, aslında düşündüğümden daha basit ama gerçek bir tuzak.
user2485710

5
@ user2485710, anahtar nokta Unix'de, kabuğun komut satırı argümanlarını komuta geçirmeden önce joker karakterleri genişletmekten sorumlu olduğudur. Windows'ta her komutun joker karakterleri kendisi genişletmesi gerekir. Bu, Unix mermilerinin herhangi bir komutla çalışan gelişmiş joker özellikler sunmasını sağlar.
cjm

2
@mikeserv, bu dosyaların o kadar önemli olmadığı gerçeğini göz önüne alarak kendimi temizlemeye koştum ve bir sonraki adıma atladım, ancak ilk yazım / sorumu düzenlediğimde göründüğü gibi şeyleri doğrulayabilirim.
user2485710

6
@mikeserv tl; dr, *tek bir argüman değil mi? Sağ? :)
Bernhard

1
@ Bernhard - aslında, bu benim karşılamadığım tek dava - çünkü olabilir .
mikeserv

18

İlk önce kabuk ./*, geçerli dizindeki tüm dosyalara genişler (nokta ile başlayan dosyalar hariç).

  • tek bir dosya yoksa veya mvbaşarısız olursa : başarısız
  • iki dosya varsa: ilki ikinciye taşınır (bu nedenle kaybolur)
  • ikiden fazla dosya varsa:
    • sonuncusu bir dizinse: tüm dosyalar bu dizine taşınır
    • Aksi halde mvbaşarısız olur.

1
Teşekkürler. Hangi alt dizinin "sonuncusu" nasıl anlaşılır?
Tim

7
Sadece çağrı echo ./*kabuğunuzun hangi sırayı kullandığını görün (genellikle alfabetik)
jofel

Bir dosya ile başarısız olursa, neden söylemiyor?
Noumenon

@ Noumenon Yorumunuzu anlamıyorum. mvYalnızca bir argümanla çağrılırsa bir hata mesajı döndürür.
jofel

Haklısın. Tarihimden gelen aynı emir, missing destination file operand after *filename*dün olmasa bile şimdi veriyor .
Noumenon

4

Yazdığınızda mv ./*, kabuk ./*çalıştırmadan önce genişleyecektir mv.

Unutulmaması gereken birkaç şey:

  • Eğer ./*az 2 argümanları içine genişletilir, mvmantıken, bir hata üretecektir.
  • ./* genellikle geçerli dizinde bulunan ve bir nokta ile başlamayan her dosyaya (dizin dahil) genişler.
  • ./*Kabuğunuzun belgelerini okuyarak neyin genişleyeceğini kontrol edebilirsiniz ( man 7 globkonunun giriş noktasıdır). Farklı mermilerin farklı seçenekleri olacaktır.

1

Ne yapar mv *?

İşte daha kısa bir cevap:

Kabuk, joker karakterini *dizin içeriğinin bir listesine genişletir . Ardından kabuk bu tam listeyi komuta iletir. Komut asla görmez *.

Komut mv file1 file2 ... filen directory, file1 ... filen'i dizine taşıyacaktır.

Örnek

Burada üç dosya içeren bir test dizini yapıyorum

$ mkdir t
$ cd t
$ echo a>a; echo b>b; echo c>c
$ ls
a  b  c

Birden fazla dosyayı tek bir dosyaya taşıyamazsınız

$ mv *
mv: target `c' is not a directory

Bir alt dizin ekleyelim

$ mkdir d

Sen edebilir bir subdiretory içine birden fazla dosya taşımak

$ mv *
$ ls
d
$ ls d
a  b  c

Komutun mv file1 file2 ... filen directoryyapacak bir şeyi olması çok az olası *.
mikeserv

@Mike: Cevabım, kabuk genişlemesinin son aşamasının , ikincisini etkili bir şekilde öncekine dönüştürdüğünü belirtiyor . Bunu bilmemek OP'nin kargaşasının kökü gibi görünüyor.
RedGrittyBrick

evet, ama benim açımdan genişletmek olmaz kabuk *içine file dirhangi bazı yerel olmadığı sürece dizler f.
mikeserv

@mikeserv: Böyle bir yerel ayar var, örneğim bir CentOS 5.6 GNU / Linux sistemine bağlanan Putty'den bir kes & yapıştır.
RedGrittyBrick

bu hangi yerel ayar? senin örneğin a b c ddeğil file ... dir. Ben sadece yorum yaptım çünkü herhangi bir yerdeki sıralamadan bahsetmiyorsunuz ve sadece gerçekleşmeyen şeyler *oluyor diyorsunuz file ... dir.
mikeserv
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.