マルチラインモード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

最後のスクリプトで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秒しかかかりませんでしたが、xargsforループのバージョンは42分かかりました。また、これが問題にならないようにxargsパラメータリストを複数のコマンドに分割できることに驚きました。Argument list too long

関連情報