Có một lớp lót nào cho phép tôi tạo một thư mục và di chuyển vào đó cùng một lúc không?


150

Tôi thấy mình lặp đi lặp lại rất nhiều:

mkdir longtitleproject
cd longtitleproject

Có cách nào để làm điều đó trong một dòng mà không lặp lại tên thư mục? Tôi đang ở đây




1
mkdir longtitleprojectsau đócd !^
dùng262826

Câu trả lời:


160

Không có lệnh tích hợp, nhưng bạn có thể dễ dàng viết một hàm gọi mkdirsau đó cd:

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

Đặt mã này vào ~/.bashrctệp của bạn (hoặc ~/.kshrccho người dùng ksh hoặc ~/.zshrccho người dùng zsh). Nó định nghĩa một hàm gọi là mkcd. "$1"sẽ được thay thế bằng đối số của hàm khi bạn chạy nó.

Phiên bản đơn giản này có một số khuyết điểm:

  • Bạn không thể tạo một chuỗi các thư mục con cùng một lúc. Khắc phục: chuyển -ptùy chọn sang mkdir. (Điều này có thể hoặc không thể mong muốn, vì nó làm tăng nguy cơ lỗi đánh máy không bị phát hiện, ví dụ như mkcd mydierctory/newsubsẽ vui vẻ tạo mydierctorymydierctory/newsubkhi bạn định tạo newsubbên trong hiện tại mydirectory.)
  • Nếu đối số bắt đầu bằng -nhưng không chỉ -, thì mkdircdsẽ diễn giải nó như một tùy chọn. Nếu nó chỉ -, sau đó cdsẽ giải thích nó có nghĩa $OLDPWD. Nếu nó được +theo sau bởi 0 hoặc nhiều chữ số, thì cdtrong zsh sẽ hiểu nó là một chỉ mục trong ngăn xếp thư mục. Bạn có thể khắc phục vấn đề đầu tiên, nhưng không phải là hai vấn đề khác, bằng cách vượt qua --trước đối số. Bạn có thể khắc phục tất cả các vấn đề này bằng cách thêm vào ./đối số nếu đó là đường dẫn tương đối.
  • mkdirkhông tuân theo CDPATH, nhưng cdthực tế, vì vậy nếu bạn đã đặt CDPATHthành một giá trị không bắt đầu bằng .(một cấu hình hơi khác thường được thừa nhận), thì cdcó thể đưa bạn đến một thư mục khác với thư mục vừa tạo. Chuẩn bị ./cho các đường dẫn tương đối sửa lỗi này (nó gây ra CDPATHbị bỏ qua).
  • Nếu mkdirthất bại, nó cố gắng thực hiện cd. Khắc phục: sử dụng &&để tách hai lệnh.

Vẫn khá đơn giản:

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

Phiên bản này vẫn có khả năng cdđi vào một thư mục khác với thư mục mkdirvừa tạo trong một trường hợp cạnh: nếu đối số mkcdchứa ..và đi qua một liên kết tượng trưng. Ví dụ: nếu thư mục hiện tại là /tmp/heremylinklà một liên kết tượng trưng đến /somewhere/else, sau đó mkdir mylink/../footạo /somewhere/else/footrong khi cd mylink/../foothay đổi thành foo. Không đủ để tìm kiếm các liên kết tượng trưng trong đối số, vì trình bao cũng theo dõi các liên kết tượng trưng trong thư mục hiện tại của chính nó, vì vậy cd /tmp/mylink; mkdir ../foo; cd ../fookhông thay đổi thành thư mục mới ( /somewhere/else/foo) mà vào /tmp/foo. Cách khắc phục cho vấn đề này là để cho phần cddựng sẵn giải quyết tất cả các ..thành phần đường dẫn trước (nó không có ý nghĩa để sử dụng foo/..nếufookhông tồn tại, vì vậy mkdirkhông bao giờ cần phải xem bất kỳ ..).

Chúng tôi đến với phiên bản mạnh mẽ này nếu hơi gory:

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
}

(Bài tập: tại sao tôi lại sử dụng một mạng con cho cdcuộc gọi đầu tiên ?)

Nếu mkdir thất bại, tôi muốn chắc chắn không thay đổi thư mục hiện tại. Thay đổi trở lại với cd - hoặc $ OLDPWD không đủ tốt nếu shell không có quyền thay đổi vào thư mục hiện tại của nó. Ngoài ra, gọi cd cập nhật OLDPWD, vì vậy chúng tôi chỉ muốn thực hiện một lần (hoặc khôi phục OLDPWD).


Cũng có những cách ít chuyên biệt hơn để không phải gõ lại từ từ dòng trước:

  • Nhập cd , sau đó Esc .(hoặc Alt+ .) để chèn đối số cuối cùng từ lệnh trước đó.
  • cd !$thực hiện cdtrên đối số cuối cùng của lệnh trước đó.
  • Nhấn Upđể gọi lại dòng lệnh trước đó, sau đó chỉnh sửa nó để thay đổi mkdirthành cd.

Cảm ơn! chiếc Esc. Có vẻ thuận tiện nhất với tôi, chuỗi khóa có ý nghĩa đặc biệt nào không?
phương pháp của

Đó chỉ là chuỗi Bash (và được kế thừa từ ksh, và cũng hoạt động theo zsh) cho "lặp lại từ cuối của lệnh trước". Tôi sử dụng nó khá thường xuyên.
geekizard

31
@Gilles Tôi bắt đầu nghĩ rằng tài khoản "Gilles" thực sự được chia sẻ bởi một nhóm chuyên gia. ;-)
Keith

@StephaneChazelas /a/b/..//thực sự sẽ làm việc nhưng không /a/b/../c. Đã sửa. Tôi đã đặt câu hỏi cho đối tượng rộng hơn.
Gilles

1
mkcd() { mkdir -p "$1" && cd "$1"; }dường như không phải là một vấn đề trong (ví dụ của tôi) 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(bao gồm thiết lập và) hiển thị /tmp/here/foođó là những gì đã được tạo (và những gì tôi mong đợi). bashtạo sai và thay đổi thành /var/tmp/somewhere/foo.
Adam Katz

134

Đây là một lớp lót mà bạn cần. Không cần cấu hình khác:

mkdir longtitleproject && cd $_

Các $_biến, trong bash, là lập luận cuối cùng trao cho các lệnh trước đó. Trong trường hợp này, tên của thư mục bạn vừa tạo. Như đã giải thích trong 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.

Sử dụng cd $_để truy xuất đối số cuối cùng của lệnh trước thay cd !$vì vì cd !$đưa ra đối số cuối cùng của lệnh trước đó trong lịch sử shell :

cd ~/
mkdir folder && cd !$

bạn kết thúc nhà (hoặc ~ /)

cd ~/
mkdir newfolder && cd $_

bạn kết thúc ở newfolder dưới nhà !! (hoặc ~ / newfolder)


23
Tại sao trên trái đất, đây không phải là câu trả lời được chấp nhận
JSmyth 24/07/2016

1
@JSmyth Tôi đồng ý, đây là một lớp lót sử dụng chức năng vỏ tự nhiên
sming

Tôi nghĩ rằng OP đang cố gắng tránh sử dụng hai lệnh. Câu trả lời này (gần như) có giá trị như đang làm mkdir foo && cd foo, không tiện dụng.
josemigallas

7
OP đang yêu cầu một lớp lót không yêu cầu lặp lại tên thư mục và đây là
Jesús Carrera

Đây là một lớp lót truyền thống mà bạn đang đề cập hoặc đã thấy người khác sử dụng trong tài liệu / hướng dẫn. Thực tế có 3 câu trả lời hoàn hảo ở đây. Cái này, cái của @ jordan-harris, và câu trả lời được chọn. Phụ thuộc vào thiết lập và sở thích của bạn.
lội

30

Nó sẽ không bao giờ xảy ra với tôi để kịch bản hành vi này bởi vì tôi nhập vào sau đây trên cơ sở gần một giờ ...

$ mkdir someDirectory<ENTER>
$ cd !$

trong đó bash vui lòng thay thế !$bằng từ cuối cùng của dòng cuối cùng; tức là tên thư mục dài mà bạn đã nhập.

Ngoài ra, hoàn thành tên tệp là bạn của bạn trong những tình huống như vậy. Nếu thư mục mới của bạn là tệp duy nhất trong thư mục, một bản sao nhanh TABsẽ cung cấp cho bạn thư mục mới mà không cần nhập lại.

Mặc dù thật tuyệt khi bash cho phép bạn tạo ra các tác vụ phổ biến như các câu trả lời khác cho thấy tôi nghĩ tốt hơn là nên tìm hiểu các tính năng chỉnh sửa dòng lệnh mà bash phải cung cấp để khi bạn làm việc trên một máy khác, bạn không bị thiếu cú ​​pháp đường mà tập lệnh tùy chỉnh của bạn cung cấp.


1
Có một nơi tốt để tìm hiểu về hầu hết các quirks bash quan trọng như thế này?
dominicbri7

@ dominicbri7 Nói chung đi kèm theo "bash chỉnh sửa dòng lệnh" Googling tương tự đưa ra kết quả như một kết quả hàng đầu web.mit.edu/gnu/doc/html/features_7.html Cụ thể hơn, $ là một ví dụ về Trình thiết kế Word thấy gnu. org / software / bash / thủ công / bashref.html # Word-Designators
Rob

17

Theo những tùy chỉnh nào bạn đã thực hiện trên hồ sơ shell của mình để tăng năng suất? , đây là cách tôi làm điều đó:

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

nó có nghĩa là nó cũng hoạt động nếu thư mục đã tồn tại.


4
Các -ptùy chọn để mkdir sẽ ngăn chặn lỗi.
glenn jackman

1
mcd là một lệnh đã có sẵn. Mặc dù bạn vừa đưa ra một ví dụ, tôi đã sử dụng nó vì nó là một chữ cái ngắn hơn mkcd.
Dharmit

@Dharmit Shah: mcdLệnh hiện có là gì? Gói hoặc dự án nào cung cấp lệnh này?
Mikel

2
mtools cung cấp lệnh mcd. Trang man của nó cho biết "Lệnh mcd được sử dụng để thay đổi thư mục làm việc mtools trên đĩa MS-DOS."
Dharmit

13

Nếu bạn sử dụng Oh My Zsh, có một lệnh được gọi là thực hiện chính xác điều này. Nó sẽ trông giống như thế này.

take myfolder

Tôi thực sự tìm thấy cái này một cách tình cờ. Tôi chỉ nhìn và nó được liệt kê trên chiếc áo này từ wiki Oh My Zsh GitHub. Đó là một lệnh khá hữu ích và dường như rất dễ dàng để tạo ra chính mình.


1
Tôi chưa bao giờ biết về take:) Hoàn hảo! btw - iTerm2 với Oh My Zsh. Thực tế có 3 câu trả lời hoàn hảo ở đây. Cái này, cái của @ jesús-carrera, và câu trả lời được chọn. Phụ thuộc vào thiết lập và sở thích của bạn.
lội

3

Hoặc bạn chỉ có thể tạo một biến ngắn khi đang di chuyển và sử dụng nó hai lần x = longproject ; mkdir $x ; cd $x- điều mà tôi thừa nhận vẫn còn dài hơn so với sử dụng hàm shellscript :)


0

Đây là một biến thể nhỏ đáng được đề cập:

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

Thêm phần này vào của bạn ~/.bash_profilevà sau đó bạn có thể sử dụng mkdirnhư bình thường (một khi bạn đã sử dụng sourcenó), ngoại trừ bây giờ nó sẽ chạy chức năng trên chứ không phải là mkdirlệnh tiêu chuẩn .

Lưu ý, điều này không xác thực đầu vào theo câu trả lời được chấp nhận bởi Gilles , nhưng chứng minh làm thế nào bạn có thể (hiệu quả) ghi đè các nội dung.

Từ các tài liệu (diễn giải nhẹ):

command mkdir [args]chạy mkdirvới argsbỏ qua bất kỳ chức năng shell có tên mkdir. Chỉ các lệnh dựng sẵn shell hoặc các lệnh được tìm thấy bằng cách tìm kiếm PATH được thực thi. Nếu có một hàm shell được đặt tên ls, chạy command lstrong hàm sẽ thực thi lệnh bên ngoài lsthay vì gọi hàm đệ quy

Tôi tin rằng builtinđạt được một kết quả tương tự command.


bạn chắc chắn nên trích dẫn$dir
Jeff Schaller

@Jeff, đồng ý, nhưng câu trả lời được chấp nhận có tất cả xác nhận cần thiết. Tôi chỉ trình bày việc sử dụng commandnhư là một thay thế.
Arj

0

Thêm chức năng trợ giúp vào BASH, ZSH hoặc KSH

Tạo mkcdlệnh cho môi trường của bạn trong một dòng

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


-1

Chỉ cần tự động hóa các câu trả lời ở trên và tạo một tập lệnh thực thi một lần:

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

echo "$fun" >> ~/.bashrc

Chỉ cần sao chép tệp này trong một tệp mới mkcd.shvà chỉ chạy một lần trong thiết bị đầu cuối bash mkcd.sh. Sau đó thực hiện source ~/.bashrcđể làm cho nó hoạt động trong phiên hiện tại.

Sau này, bạn có thể sử dụng mkcd some_dirđể tạo và nhập trực tiếp vào thư mục đó.


Bạn đề nghị viết một tập lệnh (trong một tệp) với mục đích duy nhất là nối thêm vào ~/.bashrctệp đó (với một câu trả lời đã được đưa ra)? Và làm thế nào để bạn đề nghị tạo ra mkcd.shkịch bản này ? Với một biên tập viên, có lẽ? Điều này có vẻ như nhiều công việc hơn là chỉ chỉnh sửa ~/.bashrc. Điều này có lợi thế gì so với câu trả lời được chấp nhận? Mạnh mẽ và đáng tin cậy. Tất cả đều như vậy, vì nó sẽ thất bại vì trích dẫn các vấn đề, điều này cho tôi biết rằng bạn thậm chí không thử nó.
Scott

Tôi rất tiếc phải nói nhưng có như tôi đã viết trong câu trả lời của mình, tôi đã sử dụng các câu trả lời ở trên. Nó không hoạt động. Nếu bạn không tin tôi, hãy thử nó. Và về việc không cố gắng, tôi đã sử dụng toàn bộ ngày của mình để viết các kịch bản như vậy trong bash và python ngày hôm nay.
Subleseeker

Tôi đã thử những gì bạn viết. Nó không hoạt động.
Scott
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.