Bash 3.2.52(2)가 설치된 CentOS에서는 한 디렉터리에서 다른 디렉터리로 많은 파일(모두는 아님)을 복사해야 합니다.
예를 들어 매우 긴 줄을 만들 수도 있지만 cp /"$HOME"/dir1/{file1,fil2} ... /"$HOME"/dir2
dir1에는 파일이 많기 때문에 파일을 여러 줄로 복사하는 것을 선호합니다.
편집: 목록을 수동으로 생성합니다.
이것이 어떻게 달성될 수 있습니까?
백슬래시가 없는 솔루션을 선호합니다 | 단서를 찾지 못했습니다 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
최종 스크립트에서 xargs
run 또는 한 번만 사용하면 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초밖에 걸리지 않았으나 xargs
for 루프 버전은 42분이 걸렸습니다. 또한 이것이 문제가 되지 않도록 xargs
매개변수 목록을 여러 명령으로 분할할 수 있다는 사실에 놀랐습니다 .Argument list too long