Làm cách nào tôi có thể tự tạo các lệnh shell shell của riêng mình (ví dụ: combo mkdir / cd)?


41

Tôi không thể biết mình đã ước bao nhiêu lần cho một lệnh vừa tạo thư mục vừa chuyển đến thư mục đó. Về cơ bản, tôi muốn tương đương như sau:

mkdir -p /arbitrarily/long/path; cd /arbitrarily/long/path

nhưng chỉ phải gõ /arbitrarily/long/pathmột lần, đại loại như:

mk-cd /arbitrarily/long/path

Tôi đã thử tạo một tập lệnh để làm điều này, nhưng nó chỉ thay đổi thư mục trong tập lệnh. Tôi muốn thư mục trong shell cũng đã thay đổi.

#!/bin/bash
mkdir $1
cd $1
export PWD=$PWD

Làm thế nào tôi có thể làm cho công việc này?


12
Với cd, bạn đã chọn một trường hợp đặc biệt ngay từ đầu. : D
Daniel B

2
Không chính xác những gì tôi đang tìm kiếm, nhưng cdthông tin có liên quan cực kỳ thú vị (quay lại thư mục trước bằng cách sử dụng cd -, sử dụng pushdpopdđể duy trì "ngăn xếp" thư mục): superuser.com/questions/324512/
Christopher Bottoms

8
Bạn có thể nhập mkdir -p /very/long/path, sau đó sử dụng cd, khoảng trắng, rồi nhấn Alt + .để lặp lại đối số cuối cùng, tức là tên thư mục.
choroba

2
Không phải là một câu trả lời, chỉ là một nhận xét tương tự như @ choroba: Bạn cũng có thể sử dụng mkdir -p /very/long/path; cd !#:2. Chuỗi !#:2sẽ mở rộng để đối số nr. 2 (nghĩa là đối số thứ ba /very/long/path, khi đếm bắt đầu bằng 0).
Ingo Blechschmidt

3
@IngoBlechschmidt, thậm chí còn dễ dàng hơn, vì đó là đối số cuối cùng của lệnh cuối cùng, bạn chỉ có thể sử dụng !$. Tôi sử dụng thủ thuật đặc biệt này mọi lúc, mặc dù bạn có thể làm nhiều hơn nữa với việc mở rộng lịch sử .
tự đại diện

Câu trả lời:


92

Cách đơn giản nhất là sử dụng hàm shell:

mkcd() {
    mkdir -p -- "$1" && cd -- "$1"
}

Đặt nó trong .bashrctệp của bạn để làm cho nó có sẵn cho bạn giống như một lệnh shell khác.

Lý do tại sao nó không hoạt động như một tập lệnh bên ngoài là cdthay đổi thư mục hiện tại của tập lệnh đang chạy nhưng không ảnh hưởng đến tập lệnh gọi. Đây là do thiết kế! Mỗi quá trình có thư mục làm việc riêng được kế thừa bởi con của nó, nhưng điều ngược lại là không thể.

Trừ khi là một phần của đường ống, chạy trong nền hoặc rõ ràng trong một lớp con, hàm shell không chạy trong một quy trình riêng biệt mà trong cùng một quy trình, giống như nếu lệnh đã được lấy nguồn. Shell thư mục hiện tại sau đó có thể được thay đổi bởi một chức năng.

Việc &&được sử dụng ở đây để phân tách cả hai lệnh được sử dụng có nghĩa là, nếu lệnh đầu tiên thành công ( mkdir), hãy chạy lệnh thứ hai ( cd). Do đó, nếu mkdirkhông tạo được thư mục được yêu cầu, không có điểm nào cố gắng đi vào nó. Một thông báo lỗi được in bởi mkdirvà đó là nó.

Các -ptùy chọn sử dụng với mkdirở đó để nói với tiện ích này để tạo ra bất kỳ thư mục mất tích là một phần của đường dẫn đầy đủ của tên thư mục thông qua như là đối số. Một tác dụng phụ là nếu bạn yêu cầu tạo một thư mục đã có sẵn, mkcdchức năng sẽ không thất bại và bạn sẽ kết thúc trong thư mục đó. Đó có thể được coi là một vấn đề hoặc một tính năng. Trong trường hợp trước, chức năng có thể được sửa đổi, ví dụ như cách đơn giản cảnh báo người dùng:

mkcd() {
    if [ -d "$1" ]; then
        printf "mkcd: warning, \"%s\" already exists\n" "$1"
    else
        mkdir -p "$1" 
    fi && cd "$1"
}

Nếu không có -ptùy chọn, hành vi của chức năng ban đầu sẽ rất khác nhau.

Nếu thư mục chứa thư mục cần tạo không tồn tại, mkdirthì chức năng đó cũng không thành công.

Nếu thư mục cần tạo đã tồn tại, mkdircũng sẽ thất bại và cdkhông được gọi.

Cuối cùng, lưu ý rằng cài đặt / xuất PWDlà vô nghĩa, vì shell đã thực hiện bên trong.

Chỉnh sửa: Tôi đã thêm --tùy chọn cho cả hai lệnh cho hàm để cho phép tên thư mục bắt đầu bằng dấu gạch ngang.


5
Bạn cũng nên thêm rằng lệnh này sẽ không có sẵn vĩnh viễn trừ khi nó được thêm vào ~/.bashrchoặc một trong các tập lệnh khởi tạo khác.
AFH

Không có cách nào trong bash để làm tương đương với tcsh alias mk-cd 'mkdir -p \!:1; cd \!:1'mà không có chức năng? Hoặc có lẽ tôi nên bắt đầu nghĩ về các hàm bash giống như các bí danh mở rộng?
Thomas Padron-McCarthy

@ ThomasPadron-McCarthy cshCơ chế truyền đối số này không được triển khai với các bí danh kiểu bourne. Chức năng thực sự là con đường để đi, linh hoạt hơn nhiều.
jlliagre

@ ThomasPadron-McCarthy - Bạn có thể muốn xem câu trả lời này , nó cung cấp một cơ chế khá khó hiểu để truy cập các tham số được truyền cho một bí danh (theo định nghĩa của bar). Một tùy chọn khác sẽ được sử dụng history 1, như trong alias mk-cd='args="$(history 1)" && args="${args#*mk-cd\ }" && mkdir -p "$args" && cd'- điều này hoạt động tốt cho ví dụ của người hỏi, nhưng không phải là một giải pháp chung, vì bất kỳ lệnh nào khác trên cùng một dòng (ví dụ: đường ống đầu ra) sẽ khiến nó bị lỗi.
AFH

3
@ ThomasPadron-McCarthy Bạn nên bắt đầu nghĩ về bí danh của tcsh giống như các hàm bị hạn chế.
Gilles 'SO- ngừng trở nên xấu xa'

32

Tôi muốn thêm một giải pháp thay thế.

Kịch bản của bạn sẽ hoạt động nếu bạn gọi nó bằng lệnh . hoặc source:

. mk-cd /arbitrarily/long/path

Nếu bạn làm điều này exporttrong kịch bản là không cần thiết. Bạn có thể bỏ qua việc gõ .bằng cách sử dụng alias:

alias mk-cd='. mk-cd'

Lý do điều này hoạt động là một tập lệnh thường chạy trong lớp vỏ phụ nên môi trường của nó bị mất khi hoàn thành, nhưng lệnh .(hoặc source) buộc nó chạy trong lớp vỏ hiện tại.

Kỹ thuật này có thể hữu ích cho các chuỗi lệnh quá phức tạp đối với một chức năng hoặc đang được phát triển và thường xuyên được chỉnh sửa: một khi aliasđã được nhập vào .bash_aliases, bạn có thể chỉnh sửa tập lệnh theo ý muốn mà không cần khởi tạo lại.

Lưu ý những điều dưới đây:-

Nếu bạn viết một tập lệnh phải được gọi bằng lệnh ./ source, có hai cách để đảm bảo điều này: -

  1. Vì một số lý do, tập lệnh được gọi với ./ sourcekhông cần thực thi, do đó, chỉ cần xóa quyền này và tập lệnh sẽ không được tìm thấy trong "$ PATH" hoặc sẽ đưa ra lỗi cấp phép nếu được gọi với đường dẫn rõ ràng.

  2. Ngoài ra, thủ thuật sau đây có thể được sử dụng ở phần đầu của tập lệnh:

bind |& read && { echo 'Must be run from "." or "source" command'; exit 1; }

Điều này hoạt động vì trong lớp vỏ phụ bindđưa ra cảnh báo, mặc dù không có trạng thái lỗi: do đó readđược sử dụng để đưa ra lỗi khi không có đầu vào.


Cảm ơn thông tin trên .. Tôi đã thực hiện . .bashrcvô số lần, nhưng không biết chính xác điều đó là gì .. Nó có giống với exportkhông?
cst1992

2
@ cst1992 - Không, các lệnh hoàn toàn khác nhau: export varsao chép biến nội bộ varvào môi trường, nơi nó được kế thừa và nhập dưới dạng một biến trong bất kỳ vỏ con nào, nhưng nó không có tác dụng đối với vỏ cha. Thông thường, một lớp vỏ con được tạo để chạy tập lệnh và mọi thay đổi mà nó thực hiện (bao gồm các biến được xuất) sẽ bị mất khi hoàn thành. Để tập lệnh đặt các biến trong trình bao, nó phải chạy trong trình bao đó và đây là điều mà .lệnh thực hiện: chạy tập lệnh mà không tạo trình bao phụ. Thật kỳ lạ, các kịch bản chạy bởi .không cần phải có sự cho phép thực thi.
AFH

Cảm ơn bạn về thông tin. Tôi khẳng định rằng bạn bao gồm thông tin này trong bài viết của bạn. Điều này rất hữu ích và thật lòng mà nói, các bình luận không đảm bảo rằng họ sẽ có mặt vào ngày mai.
cst1992

@ cst1992 - Tôi đã giải quyết câu hỏi ban đầu, nhưng tôi không muốn làm lộn xộn câu trả lời của mình với các vấn đề phụ trợ. Nếu bạn đang tìm kiếm một lời giải thích về các lệnh .exportlệnh, tiêu đề của câu hỏi này sẽ không khiến bạn mong đợi một câu trả lời ở đây, vì vậy tôi sẽ để câu trả lời của tôi đứng như vậy, nhưng cảm ơn vì nhận xét của bạn.
AFH

+1 nói chung, nhưng đặc biệt là cho bí danh. Tôi có một vài kịch bản cần có nguồn gốc và tôi luôn quên chạy chúng theo cách đó. Các bí danh chăm sóc điều đó độc đáo.
Joe

13

Không phải là một lệnh đơn lẻ, nhưng bạn không phải gõ lại tất cả các đường dẫn chỉ sử dụng !$(là đối số cuối cùng từ lệnh trước đó trong lịch sử shell).

Thí dụ:

mkdir -p /arbitrarily/long/path
cd !$

1

Bằng cách tạo bí danh . Cách rất phổ biến để tạo các lệnh của riêng bạn.

Bạn có thể tạo bí danh một cách nhanh chóng:

alias myalias='mkdir -p /arbitrarily/long/path; cd /arbitrarily/long/path'

Đó là nó. Nếu bạn muốn giữ bí danh đó vĩnh viễn (không chỉ phiên hiện tại), thì hãy đặt lệnh đó trong một dotfile (thường là ~ / .bash_aliases hoặc ~ / .bash_profile).


4
Vì tên thư mục dài được mã hóa cứng, bí danh này sẽ không hữu ích trừ khi thư mục này thường xuyên bị phá hủy bởi một số quy trình khác.
jlliagre

1

Ngoài những gì đã được đề xuất, tôi muốn giới thiệu thefuck . Đó là một khung Python để hợp lý hóa quy trình shell của bạn bằng cách sửa lỗi. Lấy cảm hứng từ tweet này , tất cả những gì bạn phải làm là nhập bí danh được cấu hình của bạn (theo mặc định fuck) và nó sẽ cố gắng sửa lệnh trước đó của bạn. Một trong những sửa chữa của nó hoạt động như sau:

/etc $ cd somedir
bash: cd: No such file or directory
/etc $ fuck
mkdir somedir && cd somedir
/etc/somedir $ 
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.