存在しない場合にmvに移動先のディレクトリを作成させる方法はありますか?


275

したがって、ホームディレクトリにいてfoo.cを〜/ bar / baz / foo.cに移動したいが、それらのディレクトリが存在しない場合、これらのディレクトリを自動的に作成する方法があるので、入力するだけです

mv foo.c ~/bar/baz/ 

そしてすべてがうまくいくでしょうか?それらのディレクトリが存在するかどうかを確認し、そうでない場合はmkdirを呼び出してからmvを呼び出す単純なbashスクリプトにmvをエイリアスできるようですが、私は誰かがより良いアイデアを持っているかどうか確認するつもりだと思いました。


回答:


294

(bashで)このワンライナーはどうですか:

mkdir --parents ./some/path/; mv yourfile.txt $_

それを分解する:

mkdir --parents ./some/path

ディレクトリ(すべての中間ディレクトリを含む)を作成し、その後、次のようにします。

mv yourfile.txt $_

ファイルをそのディレクトリに移動します($ _は、前のシェルコマンドに渡された最後の引数、つまり新しく作成されたディレクトリに展開されます)。

他のシェルでこれがどの程度機能するかはわかりませんが、何を探すべきかについていくつかのアイデアが得られるかもしれません。

このテクニックを使用した例を次に示します。

$ > ls
$ > touch yourfile.txt
$ > ls
yourfile.txt
$ > mkdir --parents ./some/path/; mv yourfile.txt $_
$ > ls -F
some/
$ > ls some/path/
yourfile.txt


1
なぜ./どこでも冗長に執着しているのですか?argsは、.ディレクトリのないPATHのコマンドではありません...
Jens

3
初心者の場合、-parentsは-pに短縮できます
sakurashinken

8
奇妙なことに、--parentsmacOS 10.13.2では利用できません。を使用する必要があります-p
ジョシュア・ピンター

1
./some/path/fooなどのファイルを移動する場合は機能しません。この場合、コマンドは次のようになりますmkdir -p ./some/path/foo; mv yourfile.txt $_:h
hhbilly

63
mkdir -p `dirname /destination/moved_file_name.txt`  
mv /full/path/the/file.txt  /destination/moved_file_name.txt

2
このコードが意味をなさないことに気付いたのは私だけですか?既存のファイルへの絶対パスを再帰的に作成し(つまり、このパスがすでに存在することを意味します)、ファイルを場所(例では存在しません)に移動します。
vdegenne

1
@ user544262772 GNU coreutils dirnameは、引数が存在する必要はなく、純粋な文字列操作です。他のディストリビューションについて話すことはできません。このコードに問題はありません。
TroyHurts 2018年

これが最も簡単に自動化される答えだと思います。for f in *.txt; do mkdir -p `dirname /destination/${f//regex/repl}`; mv "$f" "/destination/${f//regex/repl}; done
カイル

23

mvまたはmv.shという名前のスクリプトとして保存します

#!/bin/bash
# mv.sh
dir="$2"
tmp="$2"; tmp="${tmp: -1}"
[ "$tmp" != "/" ] && dir="$(dirname "$2")"
[ -a "$dir" ] ||
mkdir -p "$dir" &&
mv "$@"

または、新しい端末ごとにデフォルトのmvを置き換える関数として〜/ .bashrcファイルの最後に置きます。関数を使用すると、毎回スクリプトファイルを読み取る必要がなく、bashがメモリを保持できます。

function mv ()
{
    dir="$2"
    tmp="$2"; tmp="${tmp: -1}"
    [ "$tmp" != "/" ] && dir="$(dirname "$2")"
    [ -a "$dir" ] ||
    mkdir -p "$dir" &&
    mv "$@"
}

これらはクリス・ルッツの提出に基づいています。


3
これは最も正確に私見に質問に答えます。ユーザーは拡張mvコマンドを望んでいます。特にスクリプト作成に役立ちます。つまり、必ずしもチェックを実行mkdir -pし、使用する必要があるときに実行する必要はありませんmv。しかし、のデフォルトのエラー動作が必要なのでmv、関数名をmvp- に変更しました。これにより、いつディレクトリを作成できるかがわかります。
ブライアンダンカン

最良のソリューションのアイデアのようですが、実装は非常にクラッシュします。
Ulises Layera 2015

2
@UlisesLayeraアルゴリズムを変更して、より堅牢にしました。今はクラッシュしないはずです
Sepero、

誰かが[ ! -a "$dir" ]私が右半分が真と偽で実験を行った意味を説明してもらえますか?どちらも真と評価されました.. ??? 他の理由から、tmp = "$ {tmp:-1}"は、ファイルの最後の文字を取得してパス(/)でないことを確認しているようです
bazz

@bazz「$ dirが存在しない場合は続行する」を実行する必要があります。残念ながら、あなたは正しいです。「!-a」を使用するとバグが発生します。理由はわかりません。コードを少し編集しましたが、動作するはずです。
Sepero

13

使用できますmkdir

mkdir -p ~/bar/baz/ && \
mv foo.c ~/bar/baz/

自動的に実行する簡単なスクリプト(テストされていません):

#!/bin/sh

# Grab the last argument (argument number $#)    
eval LAST_ARG=\$$#

# Strip the filename (if it exists) from the destination, getting the directory
DIR_NAME=`echo $2 | sed -e 's_/[^/]*$__'`

# Move to the directory, making the directory if necessary
mkdir -p "$DIR_NAME" || exit
mv "$@"

「$ dirname〜?bar / baz /」を実行すると、「/ home / dmckee / bar」が表示されます。これは、ここでは必要ないものです...
dmckee --- ex-moderator kitten

@dmckee、ああ、あなたは正しい。これを解決する方法について何か考えはありますか?〜/ bar / bazと入力すると、(a)〜/ bar /にコピーして名前をbazに変更するか、(b)〜/ bar / baz /にコピーします。仕事に適したツールは何ですか?
ストレージャー、2009

@dmckee、私はregexp / sedを使用して解決策を考え出しました。それはあなたの好みに合いますか?=]
ストレージャー、2009

$#= 2でない限り、$ 2が最後の引数ではないことを除いて、いいですね。最後の引数を出力するプログラムlaがあります。私はそれをcpコマンドのバージョンで使用していました(最後の引数がディレクトリでない場合に現在のディレクトリを追加するため)。最新のシェルでさえ、$ 1 .. $ 9のみをサポートしています。Perlスクリプトの方が優れている場合があります。
ジョナサンレフラー、

@Leffler、真実ではない-私はbashが9個を超える引数をサポートしていることを知っています($ {123}を使用することは1つの方法です)。私はPerlを知らないので、自由に答えてください。=]
ストレッジャー2009

7

答えは「いいえ」のようです。これを行うためだけにエイリアスやfuncを作成したくないのですが、これは1回限りであり、すでにmvコマンドを入力している最中であるためですが、そのためにうまくいくものが見つかりました。

mv *.sh  shell_files/also_with_subdir/ || mkdir -p $_

場合mv(dirが存在しません)失敗し、それは(そう、前のコマンドの最後の引数でディレクトリを作成します$_それを持っています)。したがって、このコマンドをup実行してから再実行すると、今回mvは成功するはずです。


5

次のシェルスクリプトでしょうか?

#!/bin/sh
if [[ -e $1 ]]
then
  if [[ ! -d $2 ]]
  then
    mkdir --parents $2
  fi
fi
mv $1 $2

それが基本的な部分です。引数をチェックするビットを追加したり、宛先が存在するか、ソースディレクトリが存在するか、存在しない(つまり、存在しないものを上書きしない)場合の動作を変更したい場合があります。 。


1
あなたのコードでは、ディレクトリが存在しない場合、移動は実行されません!
ストレージャー、2009

1
そして、mkdirへの「-p」フラグを逃しました。
dmckee ---元モデレーターの子猫

ディレクトリが存在しない場合、移動するだけの場合はなぜ作成するのですか?(-pフラグが修正されました)
Chris Lutz、

つまり、スクリプトを実行し、ディレクトリ$ 2が存在しない場合は作成されますが、ファイルはコピーされません。
ストレッジャー2009

彼は簡単な構成を与え、それがどのように拡張されるべきかについての情報を追加しました。なぜ反対票を投じるのか?!
ypnos 2009

5

rsyncコマンドは、宛先パスの最後のディレクトリが存在しない場合にのみトリックを実行できます。たとえば、存在するが存在しない~/bar/baz/場合の宛先パスの場合、次のコマンドを使用できます。barbaz

rsync -av --remove-source-files foo.c ~/bar/baz/

-a, --archive               archive mode; equals -rlptgoD (no -H,-A,-X)
-v, --verbose               increase verbosity
--remove-source-files   sender removes synchronized files (non-dir)

この場合、bazディレクトリが存在しない場合は作成されます。しかし、両方の場合barbazrsyncのは存在しませんが失敗します。

sending incremental file list
rsync: mkdir "/root/bar/baz" failed: No such file or directory (2)
rsync error: error in file IO (code 11) at main.c(657) [Receiver=3.1.2]

したがって、基本的にはrsync -av --remove-source-filesのエイリアスとして使用しても安全ですmv


4

これを行う最も簡単な方法は次のとおりです。

mkdir [directory name] && mv [filename] $_

ダウンロードディレクトリにあるPDFファイルをダウンロードしたとします(~/download)にし、それらをすべて存在しないディレクトリに移動したいとします(たとえば、my_PDF)ます。

次のコマンドを入力します(現在の作業ディレクトリがであることを確認してください~/download)。

mkdir my_PDF && mv *.pdf $_

次のようにサブディレクトリを作成-pするmkdirかどうかにオプションを追加できますpython:(という名前のサブディレクトリを作成したい場合):

mkdir -p my_PDF/python && mv *.pdf $_

2

Sillierですが、機能する方法:

mkdir -p $2
rmdir $2
mv $1 $2

mkdir -pを使用して、宛先ファイル名を共有する一時ディレクトリーを含むディレクトリーを作成し、単純なrmdirを使用してそのファイル名ディレクトリーを削除してから、ファイルを新しい宛先に移動します。dirnameを使用した答えがおそらく最良だと思います。


ええ、ちょっとばかげています。:-) $ 2が(元の質問のように)ディレクトリである場合、最後のディレクトリが削除されるため、「mv」は失敗します。また、$ 2がすでに存在する場合は、それも削除しようとします。
Tylla

ありがとう!これはまさに私が達成するために必要だったものです:subdirがまだ存在しないmv ./old ./subdir/new
Mike Murray

2
((cd src-path && tar --remove-files -cf - files-to-move) | ( cd dst-path && tar -xf -))

1

コード:

if [[ -e $1 && ! -e $2 ]]; then
   mkdir --parents --verbose -- "$(dirname -- "$2")"
fi
mv --verbose -- "$1" "$2"

例:

引数: "d1" "d2 / sub"

mkdir: created directory 'd2'
renamed 'd1' -> 'd2/sub'

1

これにより、親ディレクトリとともにfoo.c新しいディレクトリに移動します。bazbar

mv foo.c `mkdir -p ~/bar/baz/ && echo $_`

-pオプションmkdir必要に応じて中間ディレクトリを作成します。
なし-pパス接頭辞内のすべてのディレクトリすでに存在している必要があります。

バックティック内のすべて``が実行され、出力はコマンドの一部としてインラインで返されます。は何も返さない
ためmkdir、の出力のみecho $_がコマンドに追加されます。

$_以前に実行されたコマンドの最後の引数を参照します。
この場合、新しいディレクトリへのパスが返されます(~/bar/baz/mkdirコマンドに渡された)。


宛先を指定せずにアーカイブを解凍demo-app.zipし、現在のディレクトリからという新しいディレクトリに以外のすべてのファイルを移動したいと考えましたdemo-app
次の行でトリックを実行します。

mv `ls -A | grep -v demo-app.zip` `mkdir -p demo-app && echo $_`

ls -A隠しファイルを含むすべてのファイル名を返します(暗黙的.および..)。

パイプ記号|は、lsコマンドの出力をパイプするために使用されますgrepコマンドライン、プレーンテキスト検索ユーティリティ)。フラグは、指示を除くすべてのファイル名を検索し、返すように。 そのファイルのリストは、moveコマンドのソース引数としてコマンドラインに追加されます。target引数は、を使用して参照に渡され、を使用して出力される新しいディレクトリへのパスです。
-vgrepdemo-app.zip
mvmkdir$_echo


1
これは、詳細レベルと説明のレベルが高く、特に最初の投稿の場合です。ありがとう!
Jeremy Caney

@JeremyCaneyありがとうございます!手伝い始めてワクワクします!
エヴァンワンダー

0

ブレース拡張を使用することもできます。

mkdir -p directory{1..3}/subdirectory{1..3}/subsubdirectory{1..2}      
  • 3つのディレクトリ(directory1、directory2、directory3)を作成します。
    • そして、それらのそれぞれに2つのサブディレクトリ(サブディレクトリ1、サブディレクトリ2)、
      • そして、それぞれに2つのサブサブディレクトリ(subsubdirectory1とsubsubdirectory2)があります。

bash 3.0以降を使用する必要があります。


5
興味深いですが、OPの質問には答えません。
Alexey Feldgendler

0
$what=/path/to/file;
$dest=/dest/path;

mkdir -p "$(dirname "$dest")";
mv "$what" "$dest"

1
スタンドアロンのshスクリプトにするには、$ destと$ srcを$ 1と$ 2で
置き換えます

0

私の1つの文字列ソリューション:

test -d "/home/newdir/" || mkdir -p "/home/newdir/" && mv /home/test.txt /home/newdir/

0

コマンドをチェーンすることができます:mkdir ~/bar/baz | mv foo.c ~/bar/baz/
またはシェルスクリプトはここにあります:

#!/bin/bash
mkdir $2 | mv $1 $2

1.任意のテキストエディターを開きます
。2 .シェルスクリプトをコピーして貼り付けます。
3.保存し、それとしてmkdir_mv.shが
入力4.スクリプトのディレクトリ:cd your/script/directory
5.変更ファイルモードchmod +x mkdir_mv.sh
6セットのエイリアスalias mv="./mkdir_mv.sh"
このコマンドを実行するたびに今、mv存在しない場合は移動したディレクトリが作成されます。


0

別の答えのコメントに基づいて、これが私のシェル関数です。

# mvp = move + create parents
function mvp () {
    source="$1"
    target="$2"
    target_dir="$(dirname "$target")"
    mkdir --parents $target_dir; mv $source $target
}

これを.bashrcなどに含めて、どこでも使用できるようにします。

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