Есть ли способ заставить mv создать каталог для перемещения, если он не существует? - PullRequest
216 голосов
/ 14 февраля 2009

Итак, если я нахожусь в своем домашнем каталоге и хочу переместить foo.c в ~ / bar / baz / foo.c, но эти каталоги не существуют, есть ли способ автоматически создать эти каталоги , так что вам нужно будет только набрать

mv foo.c ~/bar/baz/ 

а все бы получилось? Похоже, вы могли бы использовать псевдоним mv для простого сценария bash, который проверял бы, существуют ли эти каталоги, а если нет, вызывал бы mkdir, а затем mv, но я подумал, что проверю, есть ли у кого-нибудь идея получше.

Ответы [ 15 ]

238 голосов
/ 14 февраля 2009

Как насчет этой однострочной (в 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
54 голосов
/ 21 июня 2012
mkdir -p `dirname /destination/moved_file_name.txt`  
mv /full/path/the/file.txt  /destination/moved_file_name.txt
20 голосов
/ 26 апреля 2012

Сохранить как скрипт с именем mv или mv.sh

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

Или поместите в конец файла ~ / .bashrc функцию, которая заменяет mv по умолчанию на каждом новом терминале. Использование функции позволяет bash сохранять память, вместо того чтобы каждый раз читать файл скрипта.

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

Они основаны на представлении Криса Лутца.

13 голосов
/ 14 февраля 2009

Вы можете использовать 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 "$@"
5 голосов
/ 14 февраля 2009

Следующий скрипт, возможно?

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

Это основная часть. Возможно, вы захотите добавить немного для проверки аргументов, и вы можете захотеть, чтобы поведение изменилось, если место назначения существует, или каталог источника существует, или не существует (т.е. не перезаписывать то, что не существует) .

4 голосов
/ 14 марта 2016

Звучит так, будто ответа нет :). На самом деле я не хочу создавать псевдоним или функцию просто для этого, часто потому, что она одноразовая, и я уже в процессе ввода команды mv, но я нашел что-то, что хорошо работает для этого: 1002 *

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

Если mv завершится неудачно (dir не существует), он создаст каталог (который является последним аргументом предыдущей команды, поэтому $_ имеет его). Так что просто запустите эту команду, затем up , чтобы перезапустить ее, и на этот раз mv должно завершиться успешно.

3 голосов
/ 07 июля 2017

Самый простой способ сделать это:

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

Давайте предположим, что я скачал pdf файлы, расположенные в моей директории загрузки (~ / download), и я хочу переместить все это в директорию, которая не выходит (скажем, "my_PDF" ).
Я наберу следующий командир (убедившись, что мой текущий рабочий каталог ~ / download):

mkdir my_PDF && mv *.pdf $_

Вы можете добавить опцию -p к mkdir, если хотите создать подкаталоги, например, так: (предполагается, что я хочу создать подкаталог с именем "python"):
mkdir -p my_PDF/python && mv *.pdf $_

2 голосов
/ 01 июля 2014

Более глупый, но рабочий способ:

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

Создайте каталог с помощью mkdir -p, включая временный каталог с общим именем файла назначения, затем удалите этот каталог с именем файла с помощью простого rmdir, а затем переместите файл в новое место назначения. Я думаю, что ответ с использованием dirname, вероятно, лучше всего.

1 голос
/ 27 февраля 2019
Команда

rsync может выполнить трюк , только если не существует последний каталог в пути назначения, например для пути назначения ~/bar/baz/, если bar существует, но baz нет, то можно использовать следующую команду:

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 будет создан, если он не существует. Но если bar и baz не существует, rsync завершится ошибкой:

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.

1 голос
/ 01 апреля 2011

Вы можете даже использовать расширения скобок:

mkdir -p directory{1..3}/subdirectory{1..3}/subsubdirectory{1..2}      
  • , который создает 3 директории (directory1, directory2, directory3),
    • и в каждом из них два подкаталога (подкаталог1, подкаталог2),
      • и в каждом из них два подкаталога (subsubdirectory1 и subsubdirectory2).

Вы должны использовать bash 3.0 или новее.

...