Apakah ada satu-liner yang memungkinkan saya untuk membuat direktori dan pindah ke sana pada saat yang sama?

150

Saya mendapati diri saya mengulangi banyak hal:

mkdir longtitleproject
cd longtitleproject

Apakah ada cara melakukannya dalam satu baris tanpa mengulangi nama direktori? Saya bash di sini.

metode tindakan
sumber
2
Terkait (tetapi lebih umum): Jalankan dua perintah pada satu argumen (tanpa skrip) .
G-Man
1
mkdir longtitleprojectlalucd !^
user262826
Juga telah dibahas di askubuntu.com/q/927463/295286 dan askubuntu.com/q/249314/295286
Sergiy Kolodyazhnyy

Jawaban:

160

Ada tidak ada built-in perintah, tetapi Anda dapat dengan mudah menulis fungsi yang memanggil mkdirmaka cd:

mkcd () {
  mkdir "$1"
  cd "$1"
}

Masukkan kode ini ke ~/.bashrcfile Anda (atau ~/.kshrcuntuk pengguna ksh, atau ~/.zshrcuntuk pengguna zsh). Ini mendefinisikan fungsi yang disebut mkcd. "$1"akan digantikan oleh argumen fungsi saat Anda menjalankannya.

Versi sederhana ini memiliki beberapa cacat:

  • Anda tidak dapat membuat rantai subdirektori sekaligus. Perbaiki: operasikan -popsi ke mkdir. (Ini mungkin atau mungkin tidak diinginkan, karena meningkatkan risiko kesalahan ketik tidak terdeteksi, misalnya mkcd mydierctory/newsubakan dengan senang hati membuat mydierctorydan mydierctory/newsubketika Anda bermaksud membuat newsubdi dalam yang ada mydirectory.)
  • Jika argumen dimulai dengan -tetapi tidak adil -, maka mkdirdan cdakan menafsirkannya sebagai opsi. Jika itu adil -, maka cdakan menafsirkannya dengan berarti $OLDPWD. Jika +diikuti oleh 0 digit atau lebih, maka cddalam zsh akan mengartikannya sebagai indeks dalam tumpukan direktori. Anda dapat memperbaiki masalah pertama, tetapi tidak dua lainnya, dengan melewati --sebelum argumen. Anda bisa memperbaiki semua masalah ini dengan menambahkan ./argumen jika itu jalan relatif.
  • mkdirtidak mengikuti CDPATH, tetapi cdmelakukannya, jadi jika Anda telah menetapkan CDPATHnilai yang tidak dimulai dengan .(konfigurasi yang agak tidak biasa), maka cdmungkin membawa Anda ke direktori yang berbeda dari yang baru saja dibuat. Mempertahankan ./lintasan relatif untuk memperbaikinya (menyebabkan CDPATHdiabaikan).
  • Jika mkdirgagal, ia mencoba mengeksekusi cd. Perbaiki: gunakan &&untuk memisahkan kedua perintah.

Masih cukup sederhana:

mkcd () {
  case "$1" in /*) :;; *) set -- "./$1";; esac
  mkdir -p "$1" && cd "$1"
}

Versi ini masih memiliki potensi untuk cdmasuk ke direktori yang berbeda dari yang mkdirbaru saja dibuat dalam satu kasus tepi: jika argumen mkcdberisi ..dan melewati tautan simbolik. Sebagai contoh, jika direktori saat ini /tmp/heredan mylinkmerupakan link simbolik ke /somewhere/else, kemudian mkdir mylink/../foomenciptakan /somewhere/else/foosedangkan cd mylink/../fooperubahan ke dalam foo. Tidak cukup hanya dengan mencari tautan simbolik dalam argumen, karena shell juga melacak tautan simbolik di direktori saat ini, jadi cd /tmp/mylink; mkdir ../foo; cd ../footidak berubah menjadi direktori baru ( /somewhere/else/foo) tetapi menjadi /tmp/foo. Perbaikan untuk ini adalah membiarkan cdbuiltin menyelesaikan semua ..komponen path terlebih dahulu (tidak masuk akal untuk digunakan foo/..jikafootidak ada, jadi mkdirtidak perlu melihat ..).

Kami datang ke versi yang kuat jika sedikit berdarah ini:

mkcd () {
  case "$1" in
    */..|*/../) cd -- "$1";; # that doesn't make any sense unless the directory already exists
    /*/../*) (cd "${1%/../*}/.." && mkdir -p "./${1##*/../}") && cd -- "$1";;
    /*) mkdir -p "$1" && cd "$1";;
    */../*) (cd "./${1%/../*}/.." && mkdir -p "./${1##*/../}") && cd "./$1";;
    ../*) (cd .. && mkdir -p "${1#.}") && cd "$1";;
    *) mkdir -p "./$1" && cd "./$1";;
  esac
}

(Latihan: mengapa saya menggunakan subkulit untuk cdpanggilan pertama ?)

Jika mkdir gagal, saya ingin memastikan untuk tidak mengubah direktori saat ini. Mengubah kembali dengan cd - atau $ OLDPWD tidak cukup baik jika shell tidak memiliki izin untuk berubah ke direktori saat ini. Juga, memanggil cd memperbarui OLDPWD, jadi kami hanya ingin melakukannya sekali (atau mengembalikan OLDPWD).


Ada juga cara yang kurang terspesialisasi untuk tidak perlu mengetik ulang kata dari baris sebelumnya:

  • Ketik cd , lalu Esc .(atau Alt+ .) untuk memasukkan argumen terakhir dari perintah sebelumnya.
  • cd !$dieksekusi cdpada argumen terakhir dari perintah sebelumnya.
  • Tekan Upuntuk memanggil kembali baris perintah sebelumnya, lalu edit untuk mengubahnya mkdirmenjadi cd.
Gilles
sumber
Terima kasih! Esc. sepertinya yang paling nyaman bagi saya, apakah urutan kunci memiliki arti khusus?
methodofaction
Itu hanya urutan Bash (dan diwarisi dari ksh, dan juga berfungsi zsh) untuk "ulangi kata terakhir dari perintah sebelumnya". Saya sering menggunakannya.
geekosaur
31
@Gilles Saya mulai berpikir bahwa akun "Gilles" sebenarnya dibagikan oleh panel ahli. ;-)
Keith
@StephaneChazelas /a/b/..//akan benar-benar berfungsi tetapi tidak /a/b/../c. Tetap. Saya telah mengajukan pertanyaan kepada audiens yang lebih luas.
Gilles
1
mkcd() { mkdir -p "$1" && cd "$1"; }tampaknya tidak menjadi masalah di (contoh saya) zsh. mkdir -p /var/tmp/somewhere/else /tmp/here; cd /tmp/here; ln -s /var/tmp/somewhere/else mylink; mkdir -p mylink/../foo && cd mylink/../foo; pwd(termasuk pengaturan dan) menampilkan /tmp/here/fooapa yang telah dibuat (dan apa yang saya harapkan). bashmembuat dan mengubah ke /var/tmp/somewhere/foo.
Adam Katz
134

Ini adalah satu-liner yang Anda butuhkan. Tidak diperlukan konfigurasi lain:

mkdir longtitleproject && cd $_

The $_variabel, di bash, adalah argumen terakhir yang diberikan kepada perintah sebelumnya. Dalam hal ini, nama direktori yang baru saja Anda buat. Sebagaimana dijelaskan dalam man bash:

_         At  shell  startup,  set to the absolute pathname used to invoke
          the shell or shell script being executed as passed in the  envi
          ronment  or  argument  list.   Subsequently, expands to the last
          argument to the previous command, after expansion.  Also set  to
          the  full  pathname  used  to  invoke  each command executed and
          placed in the environment exported to that command.  When check
          ing  mail,  this  parameter holds the name of the mail file cur
          rently being checked."$_" is the last argument of the previous command.

Gunakan cd $_untuk mengambil argumen terakhir dari perintah sebelumnya alih-alih cd !$karena cd !$memberikan argumen terakhir dari perintah sebelumnya dalam sejarah shell :

cd ~/
mkdir folder && cd !$

Anda berakhir di rumah (atau ~ /)

cd ~/
mkdir newfolder && cd $_

Anda berakhir di folder baru di bawah rumah !! (atau ~ / folder baru)

Jesús Carrera
sumber
23
Kenapa di bumi yang satu ini bukan jawaban yang diterima
JSmyth
1
@JSmyth Saya setuju, ini adalah one-liner yang menggunakan fungsionalitas shell asli
sming
Saya pikir OP sedang mencoba untuk menghindari menggunakan dua perintah. Jawaban ini (hampir) sama validnya dengan melakukan mkdir foo && cd foo, yang tidak berguna.
josemigallas
7
OP meminta liner satu yang tidak perlu mengulangi nama direktori, dan ini dia
Jesús Carrera
Ini adalah one-liner tradisional yang Anda maksudkan atau telah dilihat orang lain digunakan dalam dokumen / tutorial. Sebenarnya ada 3 jawaban sempurna di sini. Yang ini, yang oleh @ jordan-harris, dan jawaban yang dipilih. Tergantung pengaturan dan preferensi Anda.
Wade
30

Tidak pernah terpikir oleh saya untuk memperbaiki perilaku ini karena saya memasukkan yang berikut setiap jam ...

$ mkdir someDirectory<ENTER>
$ cd !$

di mana bash dengan ramah mengganti !$dengan kata terakhir dari baris terakhir; yaitu nama direktori panjang yang Anda masukkan.

Selain itu, penyelesaian nama file adalah teman Anda dalam situasi seperti itu. Jika direktori baru Anda adalah satu-satunya file dalam folder tersebut, double cepat TABakan memberi Anda direktori baru tanpa memasukkannya kembali.

Meskipun keren, bash memungkinkan Anda untuk skrip tugas-tugas umum seperti jawaban lain menyarankan saya pikir lebih baik untuk mempelajari fitur pengeditan baris perintah yang ditawarkan bash sehingga ketika Anda bekerja pada komputer lain Anda tidak kehilangan sintaksisnya gula yang disediakan skrip khusus Anda.

rampok
sumber
1
Apakah ada tempat yang baik untuk mencari tahu tentang bash quirks paling penting seperti ini?
dominicbri7
@ dominicbri7 Umumnya berada di bawah "bash command line editing" Googling sama memberikan yang berikut sebagai hasil web.mit.edu/gnu/doc/html/features_7.html Lebih khusus lagi ,! $ adalah contoh dari Designator Word, lihat gnu. org / software / bash / manual / bashref.html # Word-Designators
Rob
17

Sesuai Apa penyesuaian yang telah Anda lakukan pada profil shell Anda untuk meningkatkan produktivitas? , ini adalah bagaimana saya melakukannya:

# make a directory and cd to it
mcd()
{
    test -d "$1" || mkdir "$1" && cd "$1"
}

itu berarti juga berfungsi jika direktori sudah ada.

Mikel
sumber
4
The -ppilihan untuk mkdir akan menekan kesalahan.
glenn jackman
1
mcd adalah perintah yang sudah ada. Meskipun Anda baru saja memberikan contoh, saya menggunakannya sendiri karena suratnya lebih pendek dari mkcd.
Dharmit
@ Dharmit Shah: Apa mcdperintah yang ada ? Paket atau proyek mana yang menyediakan perintah ini?
Mikel
2
mtools menyediakan perintah mcd. Halaman manualnya mengatakan "Perintah mcd digunakan untuk mengubah direktori kerja mtools pada disk MS-DOS."
Dharmit
13

Jika Anda menggunakan Oh My Zsh, ada perintah yang disebut take yang melakukan hal ini. Akan terlihat seperti ini.

take myfolder

Saya benar-benar menemukan ini secara tidak sengaja. Saya baru saja melihat dan terdaftar di cheatsheat ini dari wiki Oh My Zsh GitHub. Ini perintah yang cukup berguna, dan tampaknya sangat mudah dibuat sendiri.

Jordan Harris
sumber
1
Saya tidak pernah tahu tentang take:) Sempurna! btw - iTerm2 dengan Oh My Zsh. Sebenarnya ada 3 jawaban sempurna di sini. Yang ini, yang oleh @ jesús-carrera, dan jawaban yang dipilih. Tergantung pengaturan dan preferensi Anda.
Wade
3

Atau Anda bisa membuat variabel pendek on-the-fly dan menggunakannya dua kali x = longproject ; mkdir $x ; cd $x- yang saya akui masih lebih lama daripada menggunakan fungsi shellscript :)

sakisk
sumber
0

Inilah sedikit varian yang layak disebutkan:

function mkdir() {
    local dir=$1
    command mkdir "$dir"  &&  cd "$dir"
}

Tambahkan ini ke Anda ~/.bash_profiledan Anda kemudian dapat menggunakan mkdirseperti biasa (setelah Anda memilikinya source), kecuali sekarang ini akan menjalankan fungsi di atas daripada mkdirperintah standar .

Catatan, ini tidak memvalidasi input sesuai jawaban yang diterima oleh Gilles , tetapi menunjukkan bagaimana Anda dapat (secara efektif) mengesampingkan builtin.

Dari dokumen (parafrase sedikit):

command mkdir [args]berjalan mkdirdengan argsmengabaikan fungsi shell yang bernama mkdir. Hanya perintah builtin shell atau perintah yang ditemukan dengan mencari PATH dieksekusi. Jika ada fungsi shell bernama ls, menjalankan command lsdalam fungsi akan menjalankan perintah eksternal lsalih-alih memanggil fungsi secara rekursif

Saya percaya builtinmencapai hasil yang mirip dengan command.

Arj
sumber
Anda harus mengutip$dir
Jeff Schaller
@ Jeff, setuju, tetapi jawaban yang diterima memiliki semua validasi yang diperlukan. Saya hanya menghadirkan penggunaan commandsebagai alternatif.
Arj
0

Menambahkan fungsi pembantu ke BASH, ZSH atau KSH

Buat mkcdperintah untuk lingkungan Anda dalam satu baris

echo -e 'mkcd() {\n mkdir -p "$1" && cd $_\n}' >> ~/.${0//-/}rc && . ~/.${0//-/}rc
Pd bulan depan
sumber
-1

Cukup otomatiskan jawaban di atas dan buat skrip yang dapat dieksekusi satu kali:

fun='
mkcd ()
{
    mkdir -p -- "$1" && cd -P -- "$1"
}'

echo "$fun" >> ~/.bashrc

Cukup salin ini di file baru mkcd.shdan jalankan hanya sekali di terminal oleh bash mkcd.sh. Kemudian jalankan source ~/.bashrcuntuk membuatnya bekerja di sesi saat ini.

Setelah ini, Anda dapat menggunakan mkcd some_diruntuk membuat dan memasukkan langsung di direktori itu.

subtleseeker
sumber
Anda menyarankan untuk menulis skrip (dalam file) yang tujuan utamanya adalah untuk menambahkan ~/.bashrcfile (dengan jawaban yang sudah diberikan)? Dan bagaimana saran Anda membuat mkcd.shskrip ini ? Dengan seorang editor, mungkin? Ini terlihat seperti lebih banyak pekerjaan daripada sekadar mengedit ~/.bashrc. Apa keuntungannya dari jawaban yang diterima? ... ... ... ... ... ... ... ... ... "..." ... "..." ... "" ... "..." ... "" Ini akan gagal karena mengutip masalah, yang mengatakan kepada saya bahwa Anda bahkan belum mencobanya sendiri.
Scott
Saya minta maaf untuk mengatakan tetapi ya karena saya menulis dalam jawaban saya, saya menggunakan jawaban di atas. Itu berhasil. Jika Anda tidak percaya kepada saya, cobalah. Dan tentang tidak mencoba, saya menggunakan hari penuh saya untuk menulis skrip tersebut dalam bash dan python hari ini.
subtleseeker
Saya sudah mencoba apa yang Anda tulis. Itu tidak bekerja.
Scott