Linux:宛先ディレクトリーが存在しない場合はコピーして作成します


347

宛先ディレクトリーが存在しない場合にそれを作成するコマンド(またはおそらくcpのオプション)が必要です。

例:

cp -? file /path/to/copy/file/to/is/very/deep/there


5
受け入れられた答えは間違っています(cpにそのようなオプションがあります)。Paul Whippによる2番目の回答を参照してください。
Ronenz 2014

1
@Ronenz、私はGNUで言及する価値のあるオプションがあることに同意しますcp(Paul Whippが回答)が、それはOPが要求するほど一般的ではありません。これは、コピーすることができますa/foo/bar/fileb/foo/bar/file、それはコピーすることはできませんfileb/foo/bar/file。(つまり、最初のファイルの場合にすでに存在していた親ディレクトリを作成するためにのみ機能しますが、任意のディレクトリを作成することはできません)
Sudo Bash

これは、cpに対する素晴らしい機能リクエストのようです。近い将来、このようなコマンドラインスイッチを取得できる可能性はありますか?
アルノー

回答:


327
mkdir -p "$d" && cp file "$d"

(そのようなオプションはありませんcp)。


62
私はあなたが必要とは思わないtest -dmkdir -pディレクトリがすでに存在していても成功する:
ephemient 2009年

おっと、右。しかし、テストは組み込みのbashである可能性があり(特に[[-d "$ d"]]と記述されている場合)、mkdirはできません;-)
Michael Krelin-ハッカー、2009年

1
mkdirBusyBoxに
組み込まれてい

7
@holms $dは、おそらく問題のディレクトリを含む変数です。つまり、3回繰り返す必要がある場合は、最初に変数に割り当てる可能性があります。
マイケルクレリン-ハッカー

237

次の両方に該当する場合:

  1. のGNUバージョンcp(たとえば、Macバージョンではない)を使用していて、かつ
  2. あなたはいくつかの既存のディレクトリ構造からコピーしていて、それを再作成する必要があるだけです

その後、の--parentsフラグでこれを行うことができますcp。(で閲覧可能な情報ページからhttp://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html#cp-invocationかとinfo cpman cp):

--parents
     Form the name of each destination file by appending to the target
     directory a slash and the specified name of the source file.  The
     last argument given to `cp' must be the name of an existing
     directory.  For example, the command:

          cp --parents a/b/c existing_dir

     copies the file `a/b/c' to `existing_dir/a/b/c', creating any
     missing intermediate directories.

例:

/tmp $ mkdir foo
/tmp $ mkdir foo/foo
/tmp $ touch foo/foo/foo.txt
/tmp $ mkdir bar
/tmp $ cp --parents foo/foo/foo.txt bar
/tmp $ ls bar/foo/foo
foo.txt

4
これはMac OS Xでは機能しないので、Linux固有のものだと思います。
OLT

7
私はgnu固有だと思います。あなたが持っているmacports場合は、coreutilsとそのをインストールできますgcp
マイケルクレリン-ハッカー

16
Man、linuxはすべてを
Ziggy

19
これは、私が探していた答え(したがって、私が賛成したもの)ですが、少し違う質問に対する答えだと思います。私は、これはこれを読んでほとんどの人が面白いであることをおそらくユースケースである、あなたは元の親ディレクトリと同じになるように先の親ディレクトリをしたいと仮定すると解決策だと思います。
デビッドWiniecki

7
これは、ディレクトリ「bar」がすでに存在することを前提としていますが、元の質問は、宛先として提供され、まだ存在しない場合に「bar」を自動的に作成する方法を示唆しています。これに対する答えは、@ MichaelKrelin-hackerによって提供されます。
thdoan 2016年

69

簡潔な答え

にコピーmyfile.txtするには/foo/bar/myfile.txt、次を使用します:

mkdir -p /foo/bar && cp myfile.txt $_

これはどのように作動しますか?

これにはいくつかのコンポーネントがあるため、すべての構文を段階的に説明します。

mkdirユーティリティは、POSIX標準で指定され、ディレクトリを作ります。-pドキュメントごとの引数により、mkdir

不足している中間パス名コンポーネントを作成します

つまり、を呼び出すとmkdir -p /foo/barmkdirが作成され/foo 存在しない/foo/bar場合/fooは作成されます。(がなければ-p、代わりにエラーがスローされます。

&&リスト演算子は、に記載されているように、POSIX標準(またはBashのマニュアルあなたが好む場合)、効果があるcp myfile.txt $_場合にのみ実行されますmkdir -p /foo/bar正常に実行します。これは、失敗する可能性のある多くの理由の1つで失敗したcp場合、コマンドは実行を試みないことを意味ます。mkdir

最後に、$_2番目の引数として渡すcp「特別なパラメータ」は、変数に格納することなく長い引数(ファイルパスなど)を繰り返さないようにするのに便利です。Bashマニュアルによると

前のコマンドの最後の引数に展開します

この場合、それが/foo/barに渡されたものmkdirです。したがって、cpコマンドはに展開され、新しく作成されたディレクトリにcp myfile.txt /foo/barコピーmyfile.txtされ/foo/barます。

はPOSIX標準の一部で$_ないことに注意してください。そのため、理論的には、Unixバリアントには、この構成をサポートしないシェルが含まれている可能性があります。ただし、サポートしていない最新のシェルについては知りません$_。確かにBash、Dash、およびzshはすべて機能します。


最後の注記:この回答の冒頭で示したコマンドは、ディレクトリ名にスペースが含まれていないことを前提としています。スペースを含む名前を処理する場合は、異なる単語が含まれるように引用符で囲む必要があります。mkdirまたはへの異なる引数として扱われませんcp。したがって、コマンドは実際には次のようになります。

mkdir -p "/my directory/name with/spaces" && cp "my filename with spaces.txt" "$_"

16
余談ですが、私は通常、スタックオーバーフローのBashまたはUnixシェルコマンドに関する詳細が欠けていることにがっかりしています。私はここで反対の極端に行くことを試みました、そして構文のすべての詳細を説明し、このものがどのように機能するかについてのドキュメントを見つけるために適切な場所にリンクします。これが少なくとも一部の人々に役立つことを願っています。また、当然のことですが、私はこのアプローチをこの回答から重複した質問に
切り刻みました

今まで$ _を見たことがない。それは何を指しますか?最後のコマンドで使用されたフォルダ?
thebunnyrules

9
@thebunnyrulesしかし...しかし... 「これはどのように機能するのですか?」私の回答のセクションには、あなたがたった今尋ねた質問に特化した複数の段落が文字どおり含まれています それは無視され愛されていないように感じます。:(
マークアメリー2018

申し訳ありません。あなたは絶対的に正しいです。私はあなたの答えの他のすべてをすでに知っていたので、すぐにそれをスキャンしました。もっと注意深く読むべきだった。
thebunnyrules

うわー、あなたは本当にその答えにたくさんの仕事を入れました...それをありがとう。学ぶのは良かったです:$ _。これからかなり自分が使っているのが見えます。プロセス全体を自動化するスクリプトを書いて、このスレッドに載せました。それをやってみる、多分あなたは好きよ:stackoverflow.com/questions/1529946/...は
thebunnyrules

39

このような古い質問ですが、別の解決策を提案できます。

installプログラムを使用してファイルをコピーし、「オンザフライ」で宛先パスを作成できます。

install -D file /path/to/copy/file/to/is/very/deep/there/file

ただし、考慮すべきいくつかの側面があります。

  1. 宛先パスだけでなく、宛先ファイル名も指定する必要があります
  2. 宛先ファイルは実行可能になります(少なくとも、テストから見た限り)。

-m宛先ファイルに権限を設定するオプションを追加することで、#2を簡単に修正できます(例:で新しいファイルを作成するのと同じように-m 664、権限rw-rw-r--で宛先ファイルを作成しますtouch)。


そして、これは私が =)に触発された答えへ恥知らずなリンクです


私の使用法では本当にうまくいきませんでしたが、クールなトリックです!覚えておきましょう。
thebunnyrules

このコマンドは、755rwxr-xr-x)権限を持つ宛先ファイルを作成することに注意してください。これはおそらく望ましくありません。あなたが何か他のものを指定することができます-mスイッチを、私はちょうどする方法を見つけることができませんでし保つファイルのパーミッションを:(
törzsmókus

19

ファイルが存在するための穴を掘るので、それを「埋め込み」コピーと呼ぶ、必要なことを行うシェル関数:

bury_copy() { mkdir -p `dirname $2` && cp "$1" "$2"; }

1
あなたも引用符で囲む必要がありdirname $2ます
TarnayKálmánOct

4
@Kalmi、適切な引用のために$2、引数として引用することもできますdirname。のようにmkdir -p "$(dirname "$2")"。これは引用せず$2にすることはcp無意味です;)
マイケルKrelin -ハッカー

3
この回答は、$ 2
がまだ

@ user467257が指摘しているように、これにはバグがあると思います。このシナリオでは$ 2がターゲットディレクトリとターゲットファイルの間で曖昧であるため、これは修正可能ではないと思います。これに対処する別の回答を投稿しました。
リッチ

@リッチ、これは修正できないことに同意しません。以下は、ファイルとディレクトリの両方で問題なく機能します。mkdir -p dirname "$2"&& cp -r "$ 1" "$ 2"; dirname $2SOはそれらをコードマーカーとして解析するため、周りのバッククォートは表示されないことに注意してください。
Yury

11

これを行う1つの方法を次に示します。

mkdir -p `dirname /path/to/copy/file/to/is/very/deep/there` \
   && cp -r file /path/to/copy/file/to/is/very/deep/there

dirname宛先ディレクトリまたはファイルの親を提供します。mkdir -p `dirname ...`はそのディレクトリを作成し、cp -rを呼び出したときに正しいベースディレクトリが配置されるようにします。

--parentsよりも優れている点は、宛先パスの最後の要素がファイル名である場合に機能することです。

そして、それはOS Xで動作します。


6

install -D file -m 644 -t /path/to/copy/file/to/is/very/deep/there


1
実際、まったく同じではありません。彼はファイル名を2回渡す必要があるため(したがって、「-t」フラグ)、ファイルに実行ビットを設定します(したがって、「-m」の例)。それは実際には質問に答えないので、彼は最高の答えであってはなりません-私のものはそうします。
Spongman 2016年

1
これは単一のファイルに対して機能します。それthereが最終的なファイルであり、最終的なサブディレクトリではないことを考慮に入れてください。
kvantour 2018

6

上記の回答を尊重して、以下のようにrsyncを使用することを好みます。

$  rsync -a directory_name /path_where_to_inject_your_directory/

例:

$ rsync -a test /usr/local/lib/

私はそれを試し、この結果に行きました:rsync -a bull / some / hoop / ti / doop / ploop RESULT rsync:mkdir "/ some / hoop / ti / doop / ploop" failed:No such file or directory(2)rsync error :main.c(675)のファイルIO(コード11)のエラー[Receiver = 3.1.2]
thebunnyrules '25

@thebunnyrules pwd コマンドでパスをチェックする必要があります (:[link](access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/…を参照))、それを命令に正しく挿入します
marcdahan

私があなたの提案を正しく理解している場合は、ソースへの完全なパスを指定することを提案しています。つまり、ファイル名だけではなく、コマンドで「$(pwd)/ bull」を使用します。問題は、rsyncがソース(bull)ではなく宛先dirを作成するときに発生するエラーです。rsyncはmkdir -pではなく、単純なmkdirを使用しているようです。
thebunnyrules 2018年

1
ちなみに、私はスクリプトで使い始めるかもしれません。お勧めいただきありがとうございます。
thebunnyrules 2018年

1
rsync よりも予測可能ですcp。たとえば、すでに存在するcp /from/somedir /to-dir場合、cpの動作が異なります。/to-dir存在する場合/to-dirは、cpが作成されます。/to-dir/some-dirそれ以外の場合は、のコンテンツのみ/from/somedirがに配置され/to-dirます。しかし、 rsyncすなわち、場合同じように動作 /to-dir/some-dirします常に作成すること。
JoeAC

5

再開して、完全に機能するソリューションを1行で示します。ファイルの名前を変更する場合は注意してください。mkdirへのクリーンなdirパスを提供する方法を含める必要があります。$ fdstはファイルまたはディレクトリです。次のコードはどのような場合でも機能するはずです。

fsrc=/tmp/myfile.unk
fdst=/tmp/dir1/dir2/dir3/myfile.txt
mkdir -p $(dirname ${fdst}) && cp -p ${fsrc} ${fdst}

またはbash固有

fsrc=/tmp/myfile.unk
fdst=/tmp/dir1/dir2/dir3/myfile.txt
mkdir -p ${fdst%/*} && cp -p ${fsrc} ${fdst}

ありがとう!これが私が必要としたものです。私の場合、宛先にディレクトリがあるかどうか、およびディレクトリが存在するかどうかがわからないので、このコードは親ディレクトリを提供し、存在しない場合でも安全に作成できます
xbmono

4

以下を.bashrcに追加するだけで、必要に応じて微調整できます。Ubuntuで動作します。

mkcp() {
    test -d "$2" || mkdir -p "$2"
    cp -r "$1" "$2"
}

たとえば、「test」ファイルを宛先ディレクトリ「d」にコピーする場合は、

mkcp test a/b/c/d

mkcpはまず宛先ディレクトリが存在するかどうかを確認し、存在しない場合は作成して、ソースファイル/ディレクトリをコピーします。


他の人が他の回答にコメントしたので、を呼び出す前にディレクトリが存在するかどうかをテストする必要はありませんmkdir -p。すでに存在していても成功します。
bfontaine 2018年

3

これは私のためにそれをします

cp -vaR ./from ./to

同意します。でman cp-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
borracciaBlu

3

私は、cp(大文字に注意)と呼ばれるcpのサポートスクリプトを作成しました。これは、まさにこれを行うことを目的としています。スクリプトは、入力したパス(宛先である最後のものを除く)にエラーがないかチェックし、問題がなければ、コピーを開始する前にmkdir -pステップを実行して宛先パスを作成します。この時点で、通常のcpユーティリティが引き継ぎ、CPで使用するすべてのスイッチ(-r、-p、-rpLなど)が直接cpにパイプされます。スクリプトを使用する前に、理解しておくべきことがいくつかあります。

  • ここのすべての情報には、CP --helpを実行してアクセスできます。CP --help-all includeのcpのスイッチ。
  • 通常のcpは、宛先パスが見つからない場合、コピーを行いません。CPを使用したタイプミスには、このようなセーフティネットはありません。あなたが目的地を作成するので、目的地のスペルを/ usrr / share / iconsまたは/ usr / share / iconと間違えた場合、それが作成されます。
  • 通常のcpは、既存のパスでの動作をモデル化する傾向があります。cp/ a / b / c / dは、dが存在するかどうかによって異なります。dが既存のフォルダーの場合、cpはbをその中にコピーし、/ c / d / bを作成します。dが存在しない場合、bはcにコピーされ、名前がdに変更されます。dは存在するがファイルであり、bがファイルの場合、bのコピーによって上書きされます。cが存在しない場合、cpはコピーを行わずに終了します。

CPには、既存のパスからキューを取得するという贅沢はありません。そのため、CPには、非常に堅固な動作パターンが必要です。CPは、コピーしているアイテムが宛先パスにドロップされ、宛先自体(別名、ソースファイル/フォルダーの名前が変更されたコピー)ではないと想定します。意味:

  • 「CP / a / b / c / d」は、dがフォルダーの場合、/ c / d / bになります。
  • / c / bのbがフォルダの場合、「CP / a / b / c / b」は/ c / b / bになります。
  • bとdの両方がファイルの場合:CP / a / b / c / dは/ c / dになります(dはbのコピーです)。同じ状況でCP / a / b / c / bについても同じです。

このデフォルトのCP動作は、「-rename」スイッチで変更できます。この場合は、

  • 「CP --rename / a / b / c / d」は、bを/ cにコピーし、コピーの名前をdに変更します。

いくつかの結びのメモ:CPと同様に、CPは、リストされている最後のパスが宛先であると想定して、一度に複数のアイテムをコピーできます。引用符を使用する限り、スペースを含むパスも処理できます。

CPは、コピーを実行する前に、入力したパスをチェックし、それらが存在することを確認します。strictモード(--strictスイッチで使用可能)では、コピーされるすべてのファイル/フォルダーが存在する必要があります。存在しない場合、コピーは行われません。リラックスモード(--relaxed)では、リストした項目の少なくとも1つが存在する場合、コピーが続行されます。リラックスモードがデフォルトです。スイッチを使用して一時的にモードを変更することも、スクリプトの先頭に変数easy_goingを設定して永続的にモードを変更することもできます。

インストール方法は次のとおりです。

非ルート端末で、以下を実行します。

sudo echo > /usr/bin/CP; sudo chmod +x /usr/bin/CP; sudo touch /usr/bin/CP
gedit admin:///usr/bin/CP 

geditで、CPユーティリティを貼り付けて保存します。

#!/bin/bash
#Regular cp works with the assumption that the destination path exists and if it doesn't, it will verify that it's parent directory does.

#eg: cp /a/b /c/d will give /c/d/b if folder path /c/d already exists but will give /c/d (where d is renamed copy of b) if /c/d doesn't exists but /c does.

#CP works differently, provided that d in /c/d isn't an existing file, it assumes that you're copying item into a folder path called /c/d and will create it if it doesn't exist. so CP /a/b /c/d will always give /c/d/b unless d is an existing file. If you put the --rename switch, it will assume that you're copying into /c and renaming the singl item you're copying from b to d at the destination. Again, if /c doesn't exist, it will be created. So CP --rename /a/b /c/d will give a /c/d and if there already a folder called /c/d, contents of b will be merged into d. 

#cp+ $source $destination
#mkdir -p /foo/bar && cp myfile "$_"

err=0 # error count
i=0 #item counter, doesn't include destination (starts at 1, ex. item1, item2 etc)
m=0 #cp switch counter (starts at 1, switch 1, switch2, etc)
n=1 # argument counter (aka the arguments inputed into script, those include both switches and items, aka: $1 $2 $3 $4 $5)
count_s=0
count_i=0
easy_going=true #determines how you deal with bad pathes in your copy, true will allow copy to continue provided one of the items being copied exists, false will exit script for one bad path. this setting can also be changed via the custom switches: --strict and --not-strict
verbal="-v"


  help="===============================================================================\
    \n         CREATIVE COPY SCRIPT (CP) -- written by thebunnyrules\
    \n===============================================================================\n
    \n This script (CP, note capital letters) is intended to supplement \
    \n your system's regular cp command (note uncapped letters). \n
    \n Script's function is to check if the destination path exists \
    \n before starting the copy. If it doesn't it will be created.\n    
    \n To make this happen, CP assumes that the item you're copying is \
    \n being dropped in the destination path and is not the destination\
    \n itself (aka, a renamed copy of the source file/folder). Meaning:\n 
    \n * \"CP /a/b /c/d\" will result in /c/d/b \
    \n * even if you write \"CP /a/b /c/b\", CP will create the path /a/b, \
    \n   resulting in /c/b/b. \n
    \n Of course, if /c/b or /c/d are existing files and /a/b is also a\
    \n file, the existing destination file will simply be overwritten. \
    \n This behavior can be changed with the \"--rename\" switch. In this\
    \n case, it's assumed that \"CP --rename /a/b /c/d\" is copying b into /c  \
    \n and renaming the copy to d.\n
    \n===============================================================================\
    \n        CP specific help: Switches and their Usages \
    \n===============================================================================\n
    \
    \n  --rename\tSee above. Ignored if copying more than one item. \n
    \n  --quiet\tCP is verbose by default. This quiets it.\n
    \n  --strict\tIf one+ of your files was not found, CP exits if\
    \n\t\tyou use --rename switch with multiple items, CP \
    \n\t\texits.\n
    \n  --relaxed\tIgnores bad paths unless they're all bad but warns\
    \n\t\tyou about them. Ignores in-appropriate rename switch\
    \n\t\twithout exiting. This is default behavior. You can \
    \n\t\tmake strict the default behavior by editing the \
    \n\t\tCP script and setting: \n
    \n\t\teasy_going=false.\n
    \n  --help-all\tShows help specific to cp (in addition to CP)."

cp_hlp="\n\nRegular cp command's switches will still work when using CP.\
    \nHere is the help out of the original cp command... \
    \n\n===============================================================================\
    \n          cp specific help: \
    \n===============================================================================\n"

outro1="\n******************************************************************************\
    \n******************************************************************************\
    \n******************************************************************************\
    \n        USE THIS SCRIPT WITH CARE, TYPOS WILL GIVE YOU PROBLEMS...\
    \n******************************************************************************\
    \n******************************* HIT q TO EXIT ********************************\
    \n******************************************************************************"


#count and classify arguments that were inputed into script, output help message if needed
while true; do
    eval input="\$$n"
    in_=${input::1}

    if [ -z "$input" -a $n = 1 ]; then input="--help"; fi 

    if [ "$input" = "-h" -o "$input" = "--help" -o "$input" = "-?" -o "$input" = "--help-all" ]; then
        if [ "$input" = "--help-all" ]; then 
            echo -e "$help"$cp_hlp > /tmp/cp.hlp 
            cp --help >> /tmp/cp.hlp
            echo -e "$outro1" >> /tmp/cp.hlp
            cat /tmp/cp.hlp|less
            cat /tmp/cp.hlp
            rm /tmp/cp.hlp
        else
            echo -e "$help" "$outro1"|less
            echo -e "$help" "$outro1"
        fi
        exit
    fi

    if [ -z "$input" ]; then
        count_i=$(expr $count_i - 1 ) # remember, last item is destination and it's not included in cound
        break 
    elif [ "$in_" = "-" ]; then
        count_s=$(expr $count_s + 1 )
    else
        count_i=$(expr $count_i + 1 )
    fi
    n=$(expr $n + 1)
done

#error condition: no items to copy or no destination
    if [ $count_i -lt 0 ]; then 
            echo "Error: You haven't listed any items for copying. Exiting." # you didn't put any items for copying
    elif [ $count_i -lt 1 ]; then
            echo "Error: Copying usually involves a destination. Exiting." # you put one item and no destination
    fi

#reset the counter and grab content of arguments, aka: switches and item paths
n=1
while true; do
        eval input="\$$n" #input=$1,$2,$3,etc...
        in_=${input::1} #first letter of $input

        if [ "$in_" = "-" ]; then
            if [ "$input" = "--rename" ]; then 
                rename=true #my custom switches
            elif [ "$input" = "--strict" ]; then 
                easy_going=false #exit script if even one of the non-destinations item is not found
            elif [ "$input" = "--relaxed" ]; then 
                easy_going=true #continue script if at least one of the non-destination items is found
            elif [ "$input" = "--quiet" ]; then 
                verbal=""
            else
                #m=$(expr $m + 1);eval switch$m="$input" #input is a switch, if it's not one of the above, assume it belongs to cp.
                switch_list="$switch_list \"$input\""
            fi                                  
        elif ! [ -z "$input" ]; then #if it's not a switch and input is not empty, it's a path
                i=$(expr $i + 1)
                if [ ! -f "$input" -a ! -d "$input" -a "$i" -le "$count_i" ]; then 
                    err=$(expr $err + 1 ); error_list="$error_list\npath does not exit: \"b\""
                else
                    if [ "$i" -le "$count_i" ]; then 
                        eval item$i="$input" 
                        item_list="$item_list \"$input\""
                    else
                        destination="$input" #destination is last items entered
                    fi
                fi
        else
            i=0
            m=0
            n=1                     
            break
        fi      
        n=$(expr $n + 1)
done

#error condition: some or all item(s) being copied don't exist. easy_going: continue if at least one item exists, warn about rest, not easy_going: exit.
#echo "err=$err count_i=$count_i"
if [ "$easy_going" != true -a $err -gt 0 -a $err != $count_i ]; then 
    echo "Some of the paths you entered are incorrect. Script is running in strict mode and will therefore exit."
    echo -e "Bad Paths: $err $error_list"
    exit
fi

if [ $err = $count_i ]; then
    echo "ALL THE PATHS you have entered are incorrect! Exiting."
    echo -e "Bad Paths: $err $error_list"
fi

#one item to one destination:
#------------------------------
#assumes that destination is folder, it does't exist, it will create it. (so copying /a/b/c/d/firefox to /e/f/firefox will result in /e/f/firefox/firefox
#if -rename switch is given, will assume that the top element of destination path is the new name for the the item being given.

#multi-item to single destination:
#------------------------------
#assumes destination is a folder, gives error if it exists and it's a file. -rename switch will be ignored.

#ERROR CONDITIONS: 
# - multiple items being sent to a destination and it's a file.
# - if -rename switch was given and multiple items are being copied, rename switch will be ignored (easy_going). if not easy_going, exit.
# - rename option but source is folder, destination is file, exit.
# - rename option but source is file and destination is folder. easy_going: option ignored.

if [ -f "$destination" ]; then
    if [ $count_i -gt 1 ]; then 
        echo "Error: You've selected a single file as a destination and are copying multiple items to it. Exiting."; exit
    elif [ -d "$item1" ]; then
        echo "Error: Your destination is a file but your source is a folder. Exiting."; exit
    fi
fi
if [ "$rename" = true ]; then
    if [ $count_i -gt 1 ]; then
        if [ $easy_going = true ]; then
            echo "Warning: you choose the rename option but are copying multiple items. Ignoring Rename option. Continuing."
        else
            echo "Error: you choose the rename option but are copying multiple items. Script running in strict mode. Exiting."; exit
        fi
    elif [ -d "$destination" -a -f "$item1" ]; then
        echo -n "Warning: you choose the rename option but source is a file and destination is a folder with the same name. "
        if [ $easy_going = true ]; then
            echo "Ignoring Rename option. Continuing."
        else
            echo "Script running in strict mode. Exiting."; exit
        fi
    else
        dest_jr=$(dirname "$destination")
        if [ -d "$destination" ]; then item_list="$item1/*";fi
        mkdir -p "$dest_jr"
    fi
else
    mkdir -p "$destination"
fi

eval cp $switch_list $verbal $item_list "$destination"

cp_err="$?"
if [ "$cp_err" != 0 ]; then 
    echo -e "Something went wrong with the copy operation. \nExit Status: $cp_err"
else 
    echo "Copy operation exited with no errors."
fi

exit

これはやり過ぎかもしれませんが、かなり効率的で、期待どおりに機能します。ありがとうございます。
Xedret

2

cp 複数の用途があります:

$ cp --help
Usage: cp [OPTION]... [-T] SOURCE DEST
  or:  cp [OPTION]... SOURCE... DIRECTORY
  or:  cp [OPTION]... -t DIRECTORY SOURCE...
Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

@AndyRossの答えは

cp SOURCE DEST

のスタイルcpですが、

cp SOURCE... DIRECTORY/

のスタイルcp

"DEST"はあいまいで、この使用法の末尾にスラッシュがない(つまり、ターゲットディレクトリがまだ存在しない)と思います。これがおそらくcp、このオプションを追加したことがない理由です。

これが、dest dirに末尾のスラッシュを強制するこの関数の私のバージョンです。

cp-p() {
  last=${@: -1}

  if [[ $# -ge 2 && "$last" == */ ]] ; then
    # cp SOURCE... DEST/
    mkdir -p "$last" && cp "$@"
  else
    echo "cp-p: (copy, creating parent dirs)"
    echo "cp-p: Usage: cp-p SOURCE... DEST/"
  fi
}

2

ちょうど同じ問題がありました。私のアプローチは、次のようにファイルをアーカイブにtarで圧縮することでした。

tar cf your_archive.tar file1 /path/to/file2 path/to/even/deeper/file3

tarは、アーカイブ内の適切な構造にファイルを自動的に保存します。走れば

tar xf your_archive.tar

ファイルは目的のディレクトリ構造に抽出されます。


1

上記のhelp_asapとspongemanで提案されているように、「install」コマンドを使用してファイルを既存のディレクトリにコピーするか、ファイルがまだ存在しない場合は新しい宛先ディレクトリを作成できます。

オプション1は、 install -D filename some/deep/directory/filename
ファイルを新規または既存のディレクトリにコピーし、ファイル名にデフォルトの755権限を付与します

オプション2 install -D filename -m640 some/deep/directory/filename
はオプション1と同じですが、ファイル名に640のアクセス許可を与えます。

オプション3 install -D filename -m640 -t some/deep/directory/
はオプション2と同じですが、ファイル名をターゲットディレクトリにターゲットするため、ファイル名をソースとターゲットの両方に書き込む必要はありません。

オプション3とinstall -D filena* -m640 -t some/deep/directory/
同様にオプション4 ですが、複数のファイルにワイルドカードを使用します。

Ubuntuでうまく機能し、2つのステップ(ディレクトリの作成とファイルのコピー)を1つのステップに結合します。


1

これは非常に遅いですが、どこか新人を助けるかもしれません。フォルダを「自動」で作成する必要がある場合は、rsyncが最適です。rsync / path / to / sourcefile / path / to / tragetdir / thatdoestexist /


0
rsync file /path/to/copy/file/to/is/very/deep/there

これは、適切な種類のがある場合は機能する可能性がありrsyncます。


これは私にとっては機能しません-destディレクトリに「そのようなファイルまたはディレクトリはありません」
Rich

0

ソースから存在しないパスにコピーする

mkdir p /destination && cp r /source/ $_

注:このコマンドはすべてのファイルをコピーします

cp –r すべてのフォルダとその内容をコピーするため

$_ 最後のコマンドで作成された宛先として機能する


0

シンプルな

cp -a * /path/to/dst/

トリックを行う必要があります。


そうではありません。「/ path / to / dst /」は事前に存在している必要があります。
Shital Shah

-1

あなたが次のようなことをしているとしましょう

cp file1.txt A / B / C / D / file.txt

A / B / C / Dは、まだ存在しないディレクトリです。

可能な解決策は次のとおりです

DIR=$(dirname A/B/C/D/file.txt)
# DIR= "A/B/C/D"
mkdir -p $DIR
cp file1.txt A/B/C/D/file.txt

お役に立てば幸いです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.