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
実行または一度だけ使用すると、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では少なくともファイル名に改行文字を含めることができるため、1つ以上のファイル名に改行文字が含まれている場合は別の区切り文字を選択する必要があります。
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