Eğer mevcut değilse taşınacak dizini mv yapmanın bir yolu var mı?


275

Yani, ev dizinimdeysem ve foo.c dosyasını ~ / bar / baz / foo.c'ye taşımak istiyorsam, ancak bu dizinler mevcut değilse, bu dizinleri otomatik olarak oluşturmanın bir yolu var mı? sadece yazmak zorunda kalırsın

mv foo.c ~/bar/baz/ 

ve her şey yolunda gider? Görünüşe göre bu dizinlerin var olup olmadığını kontrol edecek basit bir bash betiğine mas takma adınız olabilir ve eğer mkdir ve sonra mv'yi çağırırdı, ama daha iyi bir fikrin olup olmadığını görmek için kontrol edeceğimi düşündüm.


Yanıtlar:


294

Bu tek astarlıya (bashta) ne dersiniz:

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

Bunu yıkmak:

mkdir --parents ./some/path

dizini oluşturur (tüm ara dizinler dahil), bundan sonra:

mv yourfile.txt $_

dosyayı bu dizine taşır ($ _, önceki shell komutuna iletilen son argümana genişler, yani: yeni oluşturulan dizin).

Bunun diğer mermilerde ne kadar işe yarayacağından emin değilim, ama neye bakacağınıza dair bazı fikirler verebilir.

İşte bu tekniği kullanan bir örnek:

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

32
'$ _' İle güzel.
dmckee --- ex-moderator kitten

1
Neden ./her yerde gereksiz saplantı ? Args PATH .dizini olmadan komut değildir ...
Jens

3
yeni başlayanlar için,
ebeveynler

8
Tuhaf bir şekilde, --parentsmacOS 10.13.2'de mevcut değildir. Kullanmanız gerekiyor -p.
Joshua Pinter

1
Örneğin ./some/path/foo gibi bir dosyayı taşırsanız çalışmaz. Bu durumda komut şöyle olmalıdır: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
Bu kodun mantıklı olduğunu anlayan tek kişi ben miyim? Varolan dosyanın mutlak yolunu yinelemeli olarak oluşturursunuz (bu yol zaten var demektir) ve sonra dosyayı bir konuma taşırsınız (örneğinizde mevcut değildir).
vdegenne

1
@ user544262772 GNU coreutils ' dirnameargümanının var olmasını gerektirmez, saf dize manipülasyonudur. Diğer dağıtımlar için konuşamıyorum. Bu kod afaict yanlış bir şey yok.
TroyHurts

Bence en kolay otomatik cevap bu. for f in *.txt; do mkdir -p `dirname /destination/${f//regex/repl}`; mv "$f" "/destination/${f//regex/repl}; done
Kyle

23

Mv veya mv.sh adında bir komut dosyası olarak kaydet

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

Veya ~ / .bashrc dosyanızın sonuna her yeni terminalde varsayılan mv'nin yerini alan bir işlev olarak koyun. Bir işlev kullanıldığında, her seferinde bir komut dosyası okumak zorunda kalmadan bash bellekte kalmasını sağlar.

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

Bunlar Chris Lutz'un sunulmasına dayanıyordu.


3
Bu, soruyu en doğru şekilde IMHO'ya cevaplıyor. Kullanıcı gelişmiş bir mvkomut istiyor . Özellikle kodlama için kullanışlıdır, yani kontrolleri çalıştırmak mkdir -pve kullanmak istediğiniz her zaman çalıştırmak istemezsiniz mv. Ama varsayılan hata davranışı için isteyeceğim için mv, işlev adını değiştirdim mvp- ne zaman dizinler oluşturmak olabilir biliyorum.
Brian Duncan

En iyi çözüm fikri gibi görünüyor, ancak uygulama çok çöküyor.
Ulises Layera

2
@UlisesLayera Daha sağlam hale getirmek için algoritmayı değiştirdim. Şimdi
çökmemelidir

Birisi [ ! -a "$dir" ]doğru yarıyı doğru ve yanlış, her ikisi de doğru olarak değerlendirilen deneyler yaptım anlamını açıklayabilir misiniz .. ??? Başkalarının uğruna, tmp = "$ {tmp: -1}" dosyanın bir yol olmadığından emin olmak için dosyanın son karakterini
kapıyor gibi görünüyor

@bazz "$ dir yoksa o zaman devam et" olmalıdır. Ne yazık ki, haklısın, "! -A" kullanırken bir hata var ve nedenini bilmiyorum. Kodu biraz düzenledim ve şimdi çalışmalıyım.
Sepero

13

Şunları kullanabilirsiniz mkdir:

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

Otomatik olarak yapmak için basit bir komut dosyası (denenmemiş):

#!/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 "$@"

"? $ Birdizin ~ bar / baz /" Ben koşmak, ben olsun "/ home / dmckee / bar", yo ... burada istediğim değil ki
dmckee --- eski moderatör kedi yavrusu

@dmckee, Ah, haklısın. Bunu nasıl çözeceğine dair bir fikrin var mı? ~ / Bar / baz girdiyseniz (a) ~ / bar / dizinine kopyalamak ve baz olarak yeniden adlandırmak veya (b) ~ / bar / baz / dizinine kopyalamak istersiniz. İş için daha iyi bir araç nedir?
strager

@ dmckee, bir çözüm bulmak için regexp / sed kullandım. Beğeninize göre çalışıyor mu? =]
strager

Güzel, $ 2 dışında $ # = 2 olmadığı sürece son argüman değil. Son argümanını basan bir programım var. (Son bağımsız değişken bir dizin değilse geçerli dizini eklemek için) cp komutunun bir sürümünde kullanıyordum. Modern mermiler bile sadece 1 dolar ... 9 dolar; Perl betiği daha iyi olabilir.
Jonathan Leffler

@Leffler, Doğru değil - bash'ın 9'dan fazla argümanı desteklediğini biliyorum ($ {123} kullanmak bir yöntemdir). Perl'i bilmiyorum, bu yüzden kendinize bir cevap vermekten çekinmeyin. =]
strager

7

Cevap hayır gibi geliyor :). Bunu yapmak için gerçekten bir takma ad veya işlev oluşturmak istemiyorum, çünkü genellikle bir kerelik ve zaten mvkomutu yazmanın ortasındayım , ancak bunun için iyi çalışan bir şey buldum:

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

Eğer mv(dir mevcut değil) başarısız, o (yani önceki komuta son argüman olan dizini yapacak $_o vardır). Yani sadece bu komutu çalıştırın, sonra uptekrar çalıştırın ve bu sefer mvbaşarılı olmalısınız.


5

Aşağıdaki kabuk betiği belki?

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

Temel kısım bu. Argümanları kontrol etmek için biraz eklemek isteyebilirsiniz ve hedef varsa veya kaynak dizini varsa veya yoksa (yani mevcut olmayan bir şeyin üzerine yazmayın) davranışın değişmesini isteyebilirsiniz. .


1
Kodunuzda, dizin yoksa taşıma gerçekleştirilmez!
strager

1
Ve "-p" bayrağını mkdir'e kaçırdınız.
dmckee --- ex-moderatör kedi yavrusu

Bir dizin yoksa, sadece taşıyacaksanız neden oluşturursunuz? (-p bayrağı düzeltildi)
Chris Lutz

Yani, komut dosyasını çalıştırdığınızda ve $ 2 dizini mevcut olmadığında, oluşturulur ancak dosya kopyalanmaz.
Strager

basit bir yapı oluşturdu ve nasıl genişletilmesi gerektiği hakkında bilgi verdi. Neden oy veriyorsun ?!
ypnos

5

rsync komutu hile yapabilirsiniz geçen dizin yalnızca hedef yolunda hedef yolu için örneğin yoksa ~/bar/baz/eğer barmevcutsa ancakbaz mevcut değilse, aşağıdaki komut kullanılabilir:

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)

Bu durumda baz, yoksa dizin oluşturulur. Ama her ikisi debar ve bazrsync yoktur başarısız olur:

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]

Yani temelde rsync -av --remove-source-filesbir takma ad olarak kullanmak güvenli olmalıdır mv.


4

Bunu yapmanın en basit yolu:

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

Diyelim ki indirme dizinimde bulunan pdf dosyalarını indirdim ( ~/download) ve hepsini var olmayan bir dizine taşımak istiyorum (diyelim ki)my_PDF ).

Aşağıdaki komutu yazacağım (geçerli çalışma dizinimin olduğundan emin olarak ~/download):

mkdir my_PDF && mv *.pdf $_

Bunun gibi alt dizinler oluşturmak istiyorsanız -pseçeneğine ekleyebilirsiniz mkdir: (adında bir alt dizin oluşturmak istiyorum python):

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

2

Sillier, ama çalışma şekli:

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

Hedef dosya adını paylaşan geçici bir dizin de dahil olmak üzere mkdir -p ile dizini yapın, sonra bu dosya adı dizinini basit bir rmdir ile kaldırın, sonra dosyanızı yeni hedefine taşıyın. Bence dirname kullanarak cevap muhtemelen en iyisidir.


Yepp, biraz saçma. :-) $ 2 bir dizinse (orijinal soruda olduğu gibi), son dizin silineceğinden, mutsuzca başarısız olur, bu yüzden 'mv' başarısız olur. Ve eğer 2 $ zaten varsa, o da silmeye çalışır.
Tylla

Teşekkürler! Bu tam olarak başarmak için ihtiyacım olan şey: mv ./old ./subdir/new nerede altdizin henüz mevcut değil
Mike Murray

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

1

Kod:

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

Misal:

bağımsız değişkenler: "d1" "d2 / sub"

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

1

Bu , üst dizinin foo.cbulunduğu yeni dizine taşınacaktır .bazbar

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

-pSeçeneği için mkdirgerektiği gibi ara dizinleri yaratacaktır.
olmadan-pYol önekindeki tüm dizinler zaten var olmalıdır.

Geri dönüşlerin içindeki her şey ``yürütülür ve çıktı komutunuzun bir parçası olarak satır içinde döndürülür.
Yana mkdirsadece çıkış, bir şey dönmez echo $_komutuna eklenecektir.

$_son argümanı daha önce yürütülen komuta referanslar.
Bu durumda, yeni dizininizin ( ~/bar/baz/)mkdir komuta .


Bir hedef vermeden bir arşivin sıkıştırmasını açtım ve geçerli dizim dışındaki tüm dosyaları demo-app.zipadlı yeni bir dizine taşımak istedim demo-app.
Aşağıdaki satır hile yapar:

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

ls -Agizli dosyalar dahil tüm dosya adlarını döndürür ( örtük .ve.. ).

Boru sembolü |, lskomutun çıktısını grep( bir komut satırı, düz metin arama yardımcı programı ) borulamak için kullanılır . Bayrak yönlendirir bulup hariç tüm dosya adlarını dönmek için . Bu dosya listesi, komut satırımıza move komutunun kaynak bağımsız değişkenleri olarak eklenir . Hedef bağımsız değişken, kullanarak ve çıktı kullanılarak başvurulan yeni dizinin yoludur .
-vgrepdemo-app.zip
mvmkdir$_echo


1
Bu güzel bir ayrıntı ve açıklama düzeyidir ve özellikle de ilk gönderi için. Teşekkürler!
Jeremy Caney

Teşekkürler @JeremyCaney! Yardım etmeye başlamaktan heyecan duyuyorum!
Evan Wunder

0

Ayraç uzantılarını bile kullanabilirsiniz:

mkdir -p directory{1..3}/subdirectory{1..3}/subsubdirectory{1..2}      
  • 3 dizin yaratır (dizin1, dizin2, dizin3),
    • ve her birinde iki alt dizin (alt dizin1, alt dizin2),
      • ve her birinde iki alt dizin (alt dizin1 ve alt dizin2) bulunur.

Bash 3.0 veya daha yenisini kullanmalısınız.


5
İlginç, ama OP'nin sorusuna cevap vermiyor.
Alexey Feldgendler

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

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

1
bağımsız sh betiği yapmak için $ dest ve $ src yerine 1 $ ve 2 $
yazmanız yeterlidir

0

Tek dize çözümüm:

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

0

Komutları zincirleyebilirsiniz: mkdir ~/bar/baz | mv foo.c ~/bar/baz/
veya kabuk betiği burada:

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

1. Herhangi bir metin düzenleyiciyi açın
2. Kabuk betiğini kopyalayıp yapıştırın .
3. mkdir_mv.sh olarak kaydedin
4. Komut dosyanızın dizinini girin : cd your/script/directory
5. Dosya modunu değiştirin : chmod +x mkdir_mv.sh
6. Diğer adı ayarlayın : alias mv="./mkdir_mv.sh"
Şimdi, komut çalıştırdığınızda, komut mvtaşıma dizini mevcut değilse oluşturulacaktır.


0

Başka bir cevaptaki bir yoruma dayanarak, benim kabuk fonksiyonum.

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

Bunu her yerde kullanabilmeniz için .bashrc veya benzeri bir yere ekleyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.