목적지를 지정하지 않고`mv ./*`는 무엇을합니까?


27

Return 키를 누르기 전에 실수로 대상을 지정하는 것을 잊었습니다. mv ./*대상을 지정 하지 않고 현재 디렉토리 아래의 파일과 디렉토리를 어디로 이동합니까?



4
" mv1 개의 주장 을 받아들이는 것이 놀랍습니다 ."그렇지 않습니다. 을 확장 한 후 쉘이 전달한 모든 인수를 허용합니다 *.
glglgl

답변:


41

마지막 인수가 디렉토리 인 경우, 현재 작업 디렉토리의 모든 파일과 디렉토리 (이름이 점으로 시작하는 디렉토리 제외)를 해당 디렉토리로 이동했습니다. 두 개의 파일이 있으면 첫 번째 파일이 두 번째 파일을 덮어 썼을 수 있습니다.

다음은 몇 가지 데모입니다.

둘 이상의 파일과 마지막 인수는 파일입니다

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

두 개 이상의 파일과 마지막 인수는 디렉토리입니다

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

두 개의 파일

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

추가 설명

쉘은 glob ( *)를 인수로 확장합니다 mv. 글로브는 일반적으로 알파벳 순서로 확장됩니다. mv항상 파일과 디렉토리 목록을 봅니다. 글로브 자체는 절대 보지 않습니다.

이 명령 mv은 두 가지 유형의 이동을 지원합니다. 하나는 mv file ... directory입니다. 다른 하나는 mv old-file-name new-file-name(또는 mv old-file-name directory/new-file-name)입니다.


30

먼저 5 개의 파일과 1 개의 폴더를 테스트베이스로 만들겠습니다.

touch file1 file2 file3 file4 file5
mkdir folder

다음으로 테스트 명령을 실행하겠습니다. 이 -v옵션은 쉘이 실행하는 모든 명령을 인쇄하도록 지정 stderr합니다. -xI가 인쇄 같은 원하는 옵션을 지정 stderr- 하지만 나는 그것이 수행하려는 명령이 평가하지만 전에 쉘을 실행합니다.

sh -cxv 'echo mv *'

산출

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

따라서 쉘에 공급하는 명령이 echo mv *있고 확장 쉘이 실행하는 명령 뒤에 모든 파일과 폴더가 있음을 알 수 있습니다.*echo mv

기본적으로 쉘은 다음과 같이 글로브 를 확장합니다 .

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

산출

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

이것은 set [+-]fglob 함수 의 결과입니다 .

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

산출

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

따라서 쉘과 같은 기본 옵션으로 구성된 쉘에서 명령을 실행 하면 현재 디렉토리에있는 모든 파일의 인수 목록이 로케일에 따라 정렬되어 단어 mv *로 확장 *됩니다. 그것은 콜 수행 exec(ve)에 대한 mv (기본적으로) 추가 된이 인수리스트를. 그래서 mv쉘이 그것들을 움켜 잡고 분류함에 따라 모든 인수를 얻습니다. strace이러한 효과를 보는 것 외에도 다음과 같이 디버그를 다시 사용할 수 있습니다.

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

산출

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

그리고 포터블 :

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

산출

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

기본적으로 쉘은 mv디렉토리의 내용 (비어 있지 않고 이름이 시작되는 파일 / 폴더를 포함하지 않는 경우 .) 을 인수 목록으로 사용하여 실행됩니다. mv같은 방법으로 - POSIX는이 두 개 이상의 인수로 불려 갔을 경우 디렉토리로 최종 인수를 해석하는 지정 ln입니다 (사실, 그들은 기능을 기본에 매우 유사한 도구를 것 때문에) .

echo그래도 충분합니다 .

sh -cxv 'mv *' ; ls

산출

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

모든 파일은 폴더이기 때문에 최종 인수로 이동되었습니다. 폴더가 아닌 경우 어떻게해야합니까?

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

산출

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가 지정 mv 해야하는 방식입니다.

mv [-if] source_file target_file

mv [-if] source_file... target_dir

첫 번째 시놉시스 양식에서, mv유틸리티는 source_file 피연산자에 의해 명명 된 파일을 target_file에 의해 지정된 목적지로 이동해야합니다 . 이 첫 번째 개요 양식은 최종 피연산자가 기존 디렉토리의 이름을 지정하지 않고 기존 디렉토리를 참조하는 기호 링크가 아닌 경우에 가정합니다. 이 경우, source_file 이 비 디렉토리 파일 이름을 지정하고 target_file 이 후행 /slash문자로 끝나는 mv경우이를 오류로 취급하고 source_file 피연산자가 처리 되지 않습니다 .

두 번째 개요 양식에서 mvsource_file 피연산자가 명명 한 각 파일을 target_dir 피연산자가 명명 한 기존 디렉토리의 대상 파일로 이동 하거나 target_dir 이 기존 디렉토리를 참조하는 심볼릭 링크 인 경우 참조해야합니다. 각 source_file의 대상 경로는 대상 디렉토리의 연결 /slash, 대상이로 끝나지 않은 경우 단일 문자 /slashsource_file 의 마지막 경로 이름 구성 요소입니다 . 이 두 번째 형식은 최종 피연산자가 기존 디렉토리의 이름을 지정할 때 사용됩니다.

따라서 *확장하면 :

  • 두 개의 파일

    • renamed두 번째 파일이 첫 번째 에서 두 번째 파일 인 파일은 하나만 있어야합니다 unlinked.
  • 하나 이상의 파일 다음에 디렉토리 또는 하나의 링크가 마지막에 옴

    • 하나의 디렉토리 또는 하나의 링크 만 있어야합니다. 디렉토리는 모든 상위의 이전 내용이 이동 된 곳입니다.
  • 다른 것

    • 오류 메시지와 만족스러운 한숨의 안식이 있어야합니다.

1
예, 오래된 sh것을 사용하면 디버깅을 잊어 버렸지 만 원래 질문에 관해서는 문제가 쉘이 아니라는 것을 의미 mv합니까? 그것은 불쾌합니다. 원래 생각했던 것보다 간단하지만 실제 함정입니다.
user2485710

5
@ user2485710에서 핵심은 유닉스에서 셸은 명령 행 인수를 명령에 전달하기 전에 와일드 카드 확장을 담당한다는 것입니다. Windows에서 각 명령은 와일드 카드 자체를 확장해야합니다. 이를 통해 Unix 쉘은 모든 명령에서 작동하는 고급 와일드 카드 기능을 제공 할 수 있습니다.
CJM

2
@ mikeserv는 그 파일이 그다지 중요하지 않다는 사실을 감안할 때 정리를 시작하고 다음 단계로 건너 뛰었지만 이제 첫 번째 게시물 / 질문을 편집 할 때 파일을 확인할 수 있습니다.
user2485710

6
@mikeserv tl; dr, *단일 인수가 아닙니까? 권리? :)
Bernhard

1
@Bernhard - 사실, 그게 내가 포함되지 않은 한 경우 - 그것은이 때문에 수도 합니다.
mikeserv

18

먼저 셸 ./*은 현재 디렉토리의 모든 파일로 확장 됩니다 (점으로 시작하는 파일 제외).

  • 파일이 없거나 하나만있는 경우 : mv실패
  • 두 개의 파일이있는 경우 : 첫 번째 파일이 두 번째 파일로 이동하여 손실 됨
  • 파일이 두 개 이상인 경우 :
    • 마지막 파일이 디렉토리 인 경우 : 모든 파일이이 디렉토리로 이동됩니다
    • 그렇지 않으면 mv실패합니다.

1
감사. 어떤 디렉토리가 "마지막 디렉토리"인지 어떻게 알 수 있습니까?
Tim

7
그냥 전화 echo ./*쉘 사용 (일반적으로 알파벳)를 주문 확인할 않습니다.
jofel

하나의 파일로 실패하면 왜 그렇게 말하지 않습니까?
누 메논

@Noumenon 귀하의 의견을 이해하지 못합니다. mv하나의 인수로만 호출되면 오류 메시지를 리턴합니다.
jofel

네 말이 맞아 missing destination file operand after *filename*어제 그래도 내 역사의 동일한 명령이 이제 제공합니다 .
누 메논

4

입력하면 mv ./*셸이 확장되어 ./*실행 mv됩니다.

몇 가지 참고할 사항 :

  • 경우 ./*보다 2 개 인자로 확장되고, mv논리적 오류를 생성합니다.
  • ./* 일반적으로 점으로 시작하지 않고 현재 디렉토리에있는 모든 파일 (디렉토리 포함)로 확장됩니다.
  • ./*쉘 문서를 읽어서 확장되는 내용을 제어 할 수 있습니다 ( man 7 glob주제에 대한 진입 점임). 다른 쉘에는 다른 옵션이 있습니다.

1

무엇을 mv *합니까?

더 짧은 대답은 다음과 같습니다.

쉘은 와일드 카드 *를 디렉토리 내용 목록으로 확장합니다 . 그런 다음 쉘은 해당 전체 목록을 명령에 전달합니다. 명령이 보이지 않습니다 *.

이 명령 mv file1 file2 ... filen directory은 file1 ... filen을 디렉토리로 이동합니다.

여기에 세 개의 파일을 포함하는 테스트 디렉토리를 만듭니다.

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

여러 파일을 단일 파일로 이동할 수 없습니다

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

서브 디렉토리를 추가하자

$ mkdir d

여러 파일을 하위 디렉토리로 옮길 수 있습니다

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

이 명령 mv file1 file2 ... filen directory은 전혀 관련이 거의 없습니다 *.
mikeserv

@ Mike : 내 대답은 쉘 확장 의 마지막 단계가 후자를 전자로 효과적으로 변환 한다는 것을 지적합니다 . 이것이 알지 못하는 것은 OP의 혼란의 근본으로 보입니다.
RedGrittyBrick 14

네,하지만 내 지점 확장 할 것 셸 *로는file dir 있는 일부 로케일이 없으면 d다음은 f.
mikeserv

@ mikeserv : 그런 로케일이 있습니다. 제 예제는 퍼티에서 잘라낸 페이스트로 CentOS 5.6 GNU / Linux 시스템에 연결하는 것입니다.
RedGrittyBrick

어떤 로케일입니까? 귀하의 예는 a b c d입니다 file ... dir. 나는 당신이 어디서나 정렬을 언급하지 않고 단지 그 말만하기 때문에 전혀 언급하지 않았습니다.* 하게 file ... dir발생하지 않는다.
mikeserv
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.