여러 줄 모드 cp

여러 줄 모드 cp

Bash 3.2.52(2)가 설치된 CentOS에서는 한 디렉터리에서 다른 디렉터리로 많은 파일(모두는 아님)을 복사해야 합니다.

예를 들어 매우 긴 줄을 만들 수도 있지만 cp /"$HOME"/dir1/{file1,fil2} ... /"$HOME"/dir2dir1에는 파일이 많기 때문에 파일을 여러 줄로 복사하는 것을 선호합니다.
편집: 목록을 수동으로 생성합니다.

이것이 어떻게 달성될 수 있습니까?
백슬래시가 없는 솔루션을 선호합니다 | 단서를 찾지 못했습니다 man cp| 여기에는 문서만 있는 것 같습니다.

답변1

files=(
    file1 file2 "the goose incident.png"
    "another file"
    file3 file-4 "fifth file" file6
    "this is file7 with a
newline in the middle of the name" )

cd ~/dir1 &&
cp "${files[@]}" ~/dir2

files그러면 목록에 언급된 이름이 ~/dir1에 복사됩니다 ~/dir2.

목록의 요소 사이에 있는 줄 바꿈은 files중요하지 않습니다. 단, 마지막 요소의 줄 바꿈은 파일 이름에 줄 바꿈이 포함되어 있습니다(단지 문제 없이 이러한 줄도 사용할 수 있음을 보여주기 위한 것임).

목록은 다음과 같이 작성할 수도 있습니다.

files=(
    file1
    file2
    "the goose incident.png"
    "another file"
    file3
    file-4
    "fifth file"
    file6
    "this is file7 with a
newline in the middle of the name"
)

또는

files=( file1 file2 "the goose incident.png" "another file" file3 file-4
        "fifth file" file6 "this is file7 with a
newline in the middle of the name" )

답변2

이건 어때:

#!/usr/bin/env bash

files="1
2
3
4
4
5
6
7
8
9 10 11"

IFS=$'\n'
for file in $files
do
    touch "$file"
done

touch "$file"필요한 것만 교체하세요 . 이 솔루션의 단점은 보시다시피 각 파일에 대해 새 프로세스를 생성하므로 strace많은 수의 파일에 대해 속도가 느려진다는 것입니다.

$ strace -f ./cp-here-doc.sh  |& grep 'execve("/usr/bin/touch"'
[pid 17917] execve("/usr/bin/touch", ["touch", "1"], [/* 63 vars */]) = 0
[pid 17918] execve("/usr/bin/touch", ["touch", "2"], [/* 63 vars */]) = 0
[pid 17919] execve("/usr/bin/touch", ["touch", "3"], [/* 63 vars */]) = 0
[pid 17920] execve("/usr/bin/touch", ["touch", "4"], [/* 63 vars */]) = 0
[pid 17921] execve("/usr/bin/touch", ["touch", "4"], [/* 63 vars */]) = 0
[pid 17922] execve("/usr/bin/touch", ["touch", "5"], [/* 63 vars */]) = 0
[pid 17923] execve("/usr/bin/touch", ["touch", "6"], [/* 63 vars */]) = 0
[pid 17924] execve("/usr/bin/touch", ["touch", "7"], [/* 63 vars */]) = 0
[pid 17925] execve("/usr/bin/touch", ["touch", "8"], [/* 63 vars */]) = 0
[pid 17926] execve("/usr/bin/touch", ["touch", "9 10 11"], [/* 63 vars */]) = 0

최종 스크립트에서 xargsrun 또는 한 번만 사용하면 touch스크립트를 더 빠르게 실행할 수 있습니다.cp

#!/usr/bin/env bash

files="1
2
3
4
4
5
6
7
8
9 10 11"

echo "$files" | tr '\n' '\0'  | xargs -0 touch

결과:

$ strace -f ./cp-here-doc.sh  |& grep 'execve("/usr/bin/touch"'
[pid 18290] execve("/usr/bin/touch", ["touch", "1", "2", "3", "4", "4", "5", "6", "7", "8", "9 10 11"], [/* 63 vars */]) = 0

또한 Linux에서는 최소한 파일 이름에 개행 문자가 포함될 수 있으므로, 하나 이상의 파일 이름에 개행 문자가 포함된 경우 다른 구분 기호를 선택해야 합니다.

OP가 물었다:

IFS=$'\n'은(는) 무슨 뜻인가요?

이는 문자 그대로 새로운 줄을 의미합니다. 다음 내용을 읽을 수 있습니다 man bash.

   Words of the form $'string' are treated specially.  The word
   expands to string, with backslash-escaped char- acters replaced
   as specified by the ANSI C standard.  Backslash escape
   sequences, if present, are decoded as follows:
          \a     alert (bell)
          \b     backspace
          \e
          \E     an escape character
          \f     form feed
          \n     new line

최종 스크립트는 다음과 같습니다.

#!/usr/bin/env bash

files="1
2
3
4
5
6
7
8
9 10 11"

echo "$files" | tr '\n' '\0'  | xargs -0 cp -t {} dir

나는 정말로 xargs이런 선택을 할 의향이 있다많은더 빠르고 안전합니다. 아래 Kusalananda의 의견을 참조하세요. cp명령어를 사용하여 테스트를 실행 하지는 않았지만 touch목록에서 파일 생성을 테스트했을 때 $(seq 1 1000000)16초밖에 걸리지 않았으나 xargsfor 루프 버전은 42분이 걸렸습니다. 또한 이것이 문제가 되지 않도록 xargs매개변수 목록을 여러 명령으로 분할할 수 있다는 사실에 놀랐습니다 .Argument list too long

관련 정보