Co robi `mv ./*` bez określania miejsca docelowego?

27

Przypadkowo zapomniałem podać miejsce docelowe przed naciśnięciem klawisza Return. Gdzie mv ./*bez podania miejsca docelowego przenieść pliki i katalogi z bieżącego katalogu?

Tim
źródło
4
„Jestem zaskoczony, że mvakceptuje 1 argument” Nie. Akceptuje wszystkie argumenty, które powłoka przekazała mu po rozwinięciu pliku *.
glglgl

Odpowiedzi:

41

Jeśli ostatnim argumentem był katalog, po prostu przeniosłeś wszystkie pliki i katalogi z bieżącego katalogu roboczego (oprócz tych, których nazwy zaczynają się od kropek) do tego katalogu. Jeśli były dwa pliki, pierwszy plik mógł zastąpić drugi plik.

Oto kilka demonstracji:

Więcej niż dwa pliki, a ostatnim argumentem jest plik

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

Więcej niż dwa pliki, a ostatnim argumentem jest katalog

$ 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'

Dwa pliki

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

Dalsze wyjaśnienia

Powłoka rozszerza glob ( *) na argumenty dla mv. Glob jest zwykle rozwijany w kolejności alfabetycznej. mvzawsze widzi listę plików i katalogów. Nigdy nie widzi samej globu.

Polecenie mvobsługuje dwa typy przenoszenia. Jednym jest mv file ... directory. Drugi to mv old-file-name new-file-name(lub mv old-file-name directory/new-file-name).

terdon
źródło
30

Najpierw stworzę bazę testową - 5 plików i jeden folder:

touch file1 file2 file3 file4 file5
mkdir folder

Następnie uruchomię polecenie testowe. Ta -vopcja określa, że ​​chcę, aby każde polecenie wykonywane przez powłokę było drukowane stderr. Ta -xopcja określa, że ​​chcę to samo wydrukować stderr- ale chcę, aby zrobiono to po ocenie polecenia, ale przed uruchomieniem go przez powłokę.

sh -cxv 'echo mv *'

WYDAJNOŚĆ

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

Widzicie więc, że po poleceniu, które karmię powłokę, echo mv *po poleceniu, które wykonuje powłoka po * rozwinięciu, echo mvnastępują wszystkie pliki i folder.

Domyślnie powłoka rozwija globusy, takie jak:

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

WYDAJNOŚĆ

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

Wynika to z set [+-]ffunkcji glob:

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

WYDAJNOŚĆ

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

Kiedy więc uruchomisz polecenie w powłoce skonfigurowanej z domyślnymi opcjami, takimi jak mv *powłoka, rozwija się do *słowa lista argumentów wszystkich plików w bieżącym katalogu posortowana według ustawień regionalnych. Wykonuje syscall exec(ve)dla mv (zasadniczo) z dołączoną listą argumentów. mvOtrzymuje więc wszystkie argumenty, gdy powłoka je globalizuje i sortuje. Oprócz robienia stracetych efektów, możesz ponownie użyć debugowania w następujący sposób:

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

WYDAJNOŚĆ

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

I przenośnie:

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

WYDAJNOŚĆ

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

Zasadniczo powłoka jest wykonywana mvz zawartością katalogu (jeśli nie jest pusty i nie zawiera plików / folderów o nazwach rozpoczynających się od .) jako listy argumentów. mvPOSIX jest określony interpretować jako ostatecznego argumentu katalogu, jeśli jest ona wywoływana z więcej niż dwóch argumentów - w ten sam sposób lnjest (bo w rzeczywistości są one bardzo podobne narzędzia w funkcji bazowych) .

Wystarczająco dużo echo:

sh -cxv 'mv *' ; ls

WYDAJNOŚĆ

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

Wszystkie pliki zostały przeniesione do ostatniego argumentu - ponieważ jest to folder. Co teraz, jeśli nie jest to folder?

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

WYDAJNOŚĆ

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

.:
folder/

folder:
file1  file2  file3  file4  file5

Tak określa POSIX mv w takim przypadku:

mv [-if] source_file target_file

mv [-if] source_file... target_dir

W pierwszej formie streszczenia mvnarzędzie przenosi plik nazwany przez operand plik_źródłowy do miejsca docelowego określonego przez plik_cel . Ten pierwszy formularz streszczenia zakłada się, gdy ostatni operand nie nazywa istniejącego katalogu i nie jest dowiązaniem symbolicznym odnoszącym się do istniejącego katalogu. W tym przypadku, jeśli plik_zrodlowy nazwy pliku non-katalog i target_file kończy wleczonego /slashcharakterem, mvtraktuje to jako błąd i nie ma plik_zrodlowy argumenty będą przetwarzane.

W drugim formularzu streszczenia mvprzenosi każdy plik nazwany operandem pliku źródłowego do pliku docelowego w istniejącym katalogu nazwanym przez operand katalog_docelowy lub do którego odwołuje się, jeśli katalog_docelowy jest dowiązaniem symbolicznym do istniejącego katalogu. Ścieżką docelową dla każdego pliku_źródłowego jest konkatenacja katalogu docelowego, pojedynczy /slashznak, jeśli cel nie kończy się na /slash, oraz ostatni składnik nazwy pliku źródłowego . Ta druga forma jest zakładana, gdy końcowy operand nazywa istniejący katalog.

Więc jeśli *rozwija się do:

  • dwa pliki

    • Powinieneś mieć tylko jeden plik, od pierwszego renameddo drugiego po drugim unlinked.
  • jeden lub więcej plików, a następnie ostatni katalog lub link do jednego

    • Powinieneś mieć tylko jeden katalog lub link do jednego, do którego właśnie przeniesiono całą poprzednią zawartość jego rodzica.
  • coś jeszcze

    • Powinieneś otrzymać komunikat o błędzie i satysfakcjonujące westchnienie ulgi.
mikeserv
źródło
1
tak, używając starej shrzeczy, zapomniałem o debugowaniu z tym, ale jeśli chodzi o moje oryginalne pytanie, oznacza to, że problemem nie jest powłoka mv? To paskudne, jest prostsze niż początkowo myślałem, ale to prawdziwa pułapka.
user2485710,
5
@ user2485710, kluczową kwestią jest to, że w Uniksie powłoka jest odpowiedzialna za rozwijanie symboli wieloznacznych przed przekazaniem argumentów wiersza poleceń do polecenia. W systemie Windows każde polecenie musi rozwinąć same symbole wieloznaczne. Pozwala to powłokom uniksowym oferować zaawansowane funkcje symboli wieloznacznych, które działają z dowolnymi poleceniami.
cjm
2
@mikeserv, biorąc pod uwagę fakt, że te pliki nie były tak ważne, rzuciłem się na czyszczenie i przejdź do następnego kroku, ale mogę potwierdzić rzeczy, jak teraz pojawiają się w mojej edycji mojego pierwszego postu / pytania.
user2485710,
6
@mikeserv tl; dr, czy *to nie pojedynczy argument? Dobrze? :)
Bernhard
1
@Bernhard - właściwie to jedyny przypadek, którego nie opisałem - bo może tak być.
mikeserv
18

Najpierw powłoka rozszerza się ./*na wszystkie pliki w bieżącym katalogu (z wyjątkiem plików zaczynających się od kropki).

  • w przypadku braku lub tylko jeden plik jest: mvnie
  • jeśli są dwa pliki: pierwszy jest przenoszony do drugiego (który w związku z tym ginie)
  • jeśli są więcej niż dwa pliki:
    • jeśli ostatni jest katalogiem: wszystkie pliki są przenoszone do tego katalogu
    • inaczej mvzawodzi.
Jofel
źródło
1
Dzięki. jak powiedzieć, który podkatalog jest „ostatni”?
Tim
7
Wystarczy zadzwonić echo ./*i zobaczyć, jakiej kolejności używa twoja powłoka (zwykle alfabetycznie).
jofel
Jeśli jeden plik zawiedzie, dlaczego tak nie jest?
Noumenon
@Noumenon Nie rozumiem twojego komentarza. mvzwraca komunikat o błędzie, jeśli jest wywoływany tylko z jednym argumentem.
jofel
Masz rację. To samo polecenie z mojej historii daje teraz, missing destination file operand after *filename*choć wczoraj tak nie było.
Noumenon
4

Podczas pisania mv ./*powłoka rozwija się ./*przed uruchomieniem mv.

Kilka rzeczy do zapamiętania:

  • Jeśli ./*zostanie rozwinięte do mniej niż 2 argumentów mv, logicznie spowoduje błąd.
  • ./* zwykle rozwija się do każdego pliku (w tym katalogu) obecnego w bieżącym katalogu i nie zaczyna się od kropki.
  • Możesz kontrolować, co się ./*rozwija, czytając dokumentację swojej powłoki ( man 7 globjest punktem wejścia do tematu). Różne muszle będą miały różne opcje.
rahmu
źródło
1

Co ma mv *zrobić?

Oto krótsza odpowiedź:

Powłoka rozwija symbol wieloznaczny *do listy zawartości katalogu. Następnie powłoka przekazuje tę pełną listę do polecenia. Polecenie nigdy nie widzi *.

Polecenie mv file1 file2 ... filen directoryprzeniesie plik1 ... filen do katalogu.

Przykład

Tutaj tworzę katalog testowy zawierający trzy pliki

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

Nie można przenieść wielu plików do jednego pliku

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

Dodajmy podkatalog

$ mkdir d

Państwo może przenieść wiele plików w subdiretory

$ mv *
$ ls
d
$ ls d
a  b  c
RedGrittyBrick
źródło
Polecenie mv file1 file2 ... filen directoryjest bardzo mało prawdopodobne, aby w ogóle mieć nic wspólnego z *.
mikeserv
@Mike: Moja odpowiedź wskazuje, że ostatni etap rozbudowy powłoki skutecznie przekształca ten drugi w poprzedni. Nieświadomość tego wydaje się być przyczyną zamieszania PO.
RedGrittyBrick
tak, ale chodzi mi o to, że powłoka nie rozszerzyłaby *się, file dirchyba że istnieją jakieś ustawienia regionalne, w których dnastępuje f.
mikeserv
@mikeserv: Istnieje taka lokalizacja, mój przykład to cut & paste z Putty łączącej się z systemem CentOS 5.6 GNU / Linux.
RedGrittyBrick
jakie to ustawienie regionalne? twój przykład jest taki, a b c dktóry nie jest file ... dir. I tylko komentuje w ogóle, ponieważ nie wspominając o porządek wszędzie, a tylko powiedzieć, że *staje się file ... dirco nie stało.
mikeserv