มีซับในเดียวที่อนุญาตให้ฉันสร้างไดเรคทอรีและย้ายไปยังไดเรกตอรีในเวลาเดียวกันได้หรือไม่?


150

ฉันพบว่าตัวเองกำลังทำซ้ำจำนวนมาก:

mkdir longtitleproject
cd longtitleproject

มีวิธีการทำในหนึ่งบรรทัดโดยไม่ต้องทำซ้ำชื่อไดเรกทอรีหรือไม่? ฉันทุบตีที่นี่



2
ที่เกี่ยวข้อง ( แต่โดยทั่วไปเพิ่มเติม): เรียกใช้คำสั่งที่สองในหนึ่งอาร์กิวเมนต์ (ไม่มีสคริปต์)
G-Man

1
mkdir longtitleprojectจากนั้นcd !^
user262826

นอกจากนี้ยังได้รับการคุ้มครองในaskubuntu.com/q/927463/295286 และaskubuntu.com/q/249314/295286
Sergiy Kolodyazhnyy

คำตอบ:


160

ไม่มีคำสั่งในตัว แต่คุณสามารถเขียนฟังก์ชันที่เรียกใช้mkdirแล้วcd:

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

ใส่รหัสนี้ใน~/.bashrcไฟล์ของคุณ(หรือ~/.kshrcสำหรับผู้ใช้ ksh หรือ~/.zshrcสำหรับผู้ใช้ zsh) mkcdมันกำหนดฟังก์ชั่นที่เรียกว่า "$1"จะถูกแทนที่ด้วยอาร์กิวเมนต์ของฟังก์ชั่นเมื่อคุณเรียกใช้

เวอร์ชั่นง่ายนี้มีข้อบกพร่องหลายประการ:

  • คุณไม่สามารถสร้างไดเรกทอรีย่อยได้ในครั้งเดียว แก้ไข: ผ่านการเลือกที่จะ-p mkdir(สิ่งนี้อาจเป็นที่ต้องการหรือไม่ต้องการเนื่องจากเป็นการเพิ่มความเสี่ยงของการพิมพ์ที่ไม่ถูกตรวจจับเช่นmkcd mydierctory/newsubจะสร้างความสุขmydierctoryและmydierctory/newsubเมื่อคุณต้องการสร้างnewsubภายในที่มีอยู่เดิมmydirectory)
  • หากการโต้แย้งเริ่มต้นด้วย-แต่ไม่ใช่เพียงแค่-นั้นmkdirและcdจะตีความว่าเป็นตัวเลือก ถ้ามันเป็นเพียง-แล้วจะตีความมันจะหมายถึงcd $OLDPWDหาก+ตามด้วย 0 หรือมากกว่าหลักแล้วcdใน zsh จะตีความว่ามันเป็นดัชนีในไดเรกทอรีสแต็ค คุณสามารถแก้ไขปัญหาแรก แต่ไม่ใช่อีกสองปัญหาได้โดยผ่าน--ก่อนอาร์กิวเมนต์ คุณสามารถแก้ไขปัญหาเหล่านี้ได้โดย./ต่อท้ายอาร์กิวเมนต์ถ้าเป็นเส้นทางที่สัมพันธ์กัน
  • mkdirไม่ปฏิบัติตามCDPATHแต่cdทำเช่นนั้นดังนั้นหากคุณตั้งค่าCDPATHเป็นค่าที่ไม่ได้ขึ้นต้นด้วย.(การกำหนดค่าที่ค่อนข้างผิดปกติ) คุณcdอาจนำคุณไปยังไดเรกทอรีอื่นที่ไม่ใช่ที่เพิ่งสร้างขึ้น prepending ./เส้นทางญาติแก้ไขนี้ (มันเป็นสาเหตุCDPATHที่จะละเลย)
  • หากล้มเหลวก็พยายามที่จะดำเนินการmkdir cdคงที่: ใช้&&เพื่อแยกทั้งสองคำสั่ง

ยังค่อนข้างง่าย:

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

รุ่นนี้ยังคงมีศักยภาพที่จะทำให้cdเป็นไดเรกทอรีที่แตกต่างจากที่mkdirเพิ่งสร้างขึ้นในกรณีที่ขอบ: ถ้าอาร์กิวเมนต์ที่จะmkcdมี..และผ่านการเชื่อมโยงสัญลักษณ์ ตัวอย่างเช่นถ้าไดเรกทอรีปัจจุบัน/tmp/hereและmylinkการเชื่อมโยงสัญลักษณ์ไป/somewhere/elseแล้วmkdir mylink/../fooสร้าง/somewhere/else/fooในขณะที่การเปลี่ยนแปลงลงcd mylink/../foo fooมันไม่เพียงพอที่จะมองหาการเชื่อมโยงสัญลักษณ์ในการโต้เถียงเพราะเปลือกยังติดตามการเชื่อมโยงสัญลักษณ์ในไดเรกทอรีปัจจุบันของตัวเองเพื่อcd /tmp/mylink; mkdir ../foo; cd ../fooไม่เปลี่ยนแปลงลงในไดเรกทอรีใหม่ ( /somewhere/else/foo) /tmp/fooแต่ลงไปใน การแก้ไขสำหรับสิ่งนี้คือเพื่อให้cdbuiltin แก้ไข..คอมโพเนนต์พา ธทั้งหมดก่อน (ไม่ควรใช้foo/..หากfooไม่มีอยู่ดังนั้นmkdirไม่จำเป็นต้องเห็นเลย..)

เรามาถึงเรื่องนี้หากเวอร์ชั่นเต็มไปด้วยเลือดเล็กน้อย:

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
}

(การออกกำลังกาย: ทำไมฉันถึงใช้ subshell สำหรับการcdโทรครั้งแรก?)

หาก mkdir ล้มเหลวฉันต้องการแน่ใจว่าจะไม่เปลี่ยนไดเรกทอรีปัจจุบัน เปลี่ยนกลับด้วย cd - หรือ $ OLDPWD ไม่ดีพอถ้าเชลล์ไม่ได้รับอนุญาตให้เปลี่ยนเป็นไดเรกทอรีปัจจุบัน นอกจากนี้การเรียกการอัปเดตซีดี OLDPWD ดังนั้นเราจึงต้องการทำเพียงครั้งเดียว (หรือกู้คืน OLDPWD)


นอกจากนี้ยังมีวิธีที่เชี่ยวชาญน้อยกว่าโดยไม่ต้องพิมพ์คำซ้ำจากบรรทัดก่อนหน้า:

  • พิมพ์cd แล้วEsc .(หรือAlt+ .) เพื่อแทรกอาร์กิวเมนต์ล่าสุดจากคำสั่งก่อนหน้า
  • cd !$รันcdบนอาร์กิวเมนต์สุดท้ายของคำสั่งก่อนหน้า
  • กดUpเพื่อระลึกถึงบรรทัดคำสั่งก่อนหน้านี้แล้วแก้ไขที่จะเปลี่ยนเข้าสู่mkdircd

ขอบคุณ! Esc ดูเหมือนว่าสะดวกที่สุดสำหรับฉันลำดับของคีย์มีความหมายพิเศษหรือไม่?
methodofaction

เป็นเพียงลำดับ Bash (และสืบทอดจากkshและยังทำงานได้zsh) สำหรับ "ทำซ้ำคำสุดท้ายของคำสั่งก่อนหน้า" ฉันใช้มันค่อนข้างบ่อย
geekosaur

31
@Gilles ฉันเริ่มคิดว่าบัญชี "Gilles" มีการแบ่งปันโดยคณะผู้เชี่ยวชาญ ;-)
Keith

@StephaneChazelas /a/b/..//จริงจะทำงานได้ /a/b/../cแต่ไม่ได้ แก้ไขแล้ว. ฉันตั้งคำถามให้กับผู้ชมที่กว้างขึ้น
Gilles

1
mkcd() { mkdir -p "$1" && cd "$1"; }ดูเหมือนจะไม่เป็นปัญหาใน (ตัวอย่างของฉัน) 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(รวมถึงการตั้งค่าและ) แสดง/tmp/here/fooสิ่งที่ถูกสร้างขึ้น (และสิ่งที่ฉันคาดไว้) bashสร้างและเปลี่ยนแปลง/var/tmp/somewhere/fooอย่างไม่เหมาะสม
Adam Katz

134

นี่คือหนึ่งซับที่คุณต้องการ ไม่ต้องการการกำหนดค่าอื่น ๆ :

mkdir longtitleproject && cd $_

$_ตัวแปรในทุบตีเป็นอาร์กิวเมนต์สุดท้ายที่กำหนดให้คำสั่งก่อนหน้า ในกรณีนี้ชื่อของไดเรกทอรีที่คุณเพิ่งสร้างขึ้น ตามที่อธิบายไว้ใน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.

ใช้cd $_เพื่อดึงอาร์กิวเมนต์สุดท้ายของคำสั่งก่อนหน้านี้แทนcd !$เพราะcd !$ให้อาร์กิวเมนต์สุดท้ายของคำสั่งก่อนหน้าในประวัติเชลล์ :

cd ~/
mkdir folder && cd !$

คุณท้ายบ้าน (หรือ ~ /)

cd ~/
mkdir newfolder && cd $_

คุณจบลงที่โฟลเดอร์ใหม่ภายใต้บ้าน !! (หรือ ~ / โฟลเดอร์ใหม่)


23
ทำไมบนโลกใบนี้จึงไม่ใช่คำตอบที่ยอมรับ
JSmyth

1
@JSmyth ฉันเห็นด้วยนี่เป็นหนึ่งในสายการบินที่ใช้ฟังก์ชั่นเชลล์พื้นเมือง
sming

ฉันคิดว่า OP พยายามหลีกเลี่ยงการใช้สองคำสั่ง คำตอบนี้ (เกือบ) ใช้ได้เหมือนการทำmkdir foo && cd fooซึ่งไม่สะดวก
josemigallas

7
OP ขอหนึ่งซับที่ไม่ต้องทำซ้ำชื่อไดเรกทอรีและนี่คือมัน
Jesús Carrera

นี่คือหนึ่งซับแบบดั้งเดิมที่คุณอ้างถึงหรือเคยเห็นคนอื่นใช้ในเอกสาร / แบบฝึกหัด จริงๆแล้วมี 3 คำตอบที่สมบูรณ์แบบที่นี่ อันนี้อันนี้โดย @ jordan-harris และคำตอบที่เลือก ขึ้นอยู่กับการตั้งค่าและการตั้งค่าของคุณ
ลุย

30

มันจะไม่เกิดขึ้นกับฉันที่จะเขียนสคริปต์พฤติกรรมนี้เพราะฉันป้อนต่อไปนี้ในเกือบชั่วโมง ...

$ mkdir someDirectory<ENTER>
$ cd !$

โดยที่ bash กรุณาแทนที่!$ด้วยคำสุดท้ายของบรรทัดสุดท้าย; คือชื่อไดเรกทอรีแบบยาวที่คุณป้อน

นอกจากนี้การเติมชื่อไฟล์ให้เพื่อนของคุณในสถานการณ์เช่นนี้คือ หากไดเรกทอรีใหม่ของคุณเป็นไฟล์เดียวในโฟลเดอร์ double อย่างรวดเร็วTABจะให้ไดเรกทอรีใหม่โดยไม่ต้องป้อนซ้ำ

แม้ว่ามันจะเจ๋งมากที่ bash ช่วยให้คุณสามารถสคริปต์งานทั่วไปเช่นคำตอบอื่น ๆ ขอแนะนำฉันคิดว่ามันจะดีกว่าที่จะเรียนรู้คุณสมบัติการแก้ไขบรรทัดคำสั่งที่ bash มีให้เพื่อที่ว่าเมื่อคุณทำงานกับเครื่องอื่น น้ำตาลที่สคริปต์ของคุณกำหนดเอง


1
มีสถานที่ที่ดีที่จะหาข้อมูลเกี่ยวกับทุบตีที่สำคัญที่สุดเช่นนี้หรือไม่?
dominicbri7

@ dominicbri7 โดยทั่วไปจะอยู่ภายใต้ "การแก้ไขบรรทัดคำสั่ง bash" Googling เดียวกันให้สิ่งต่อไปนี้เป็นผลลัพธ์สูงสุดweb.mit.edu/gnu/doc/html/features_7.htmlโดยเฉพาะอย่างยิ่ง! $ เป็นตัวอย่างของ Word Designator ที่ดู gnu org / software / bash / manual / bashref.html # Word-Designators
Rob

17

ตามที่คุณได้ทำการปรับแต่งในโปรไฟล์ shell เพื่อเพิ่มประสิทธิภาพ? นี่คือวิธีที่ฉันทำ:

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

มันหมายความว่ายังใช้งานได้หากไดเรกทอรีมีอยู่แล้ว


4
-pตัวเลือกในการ mkdir จะยกเลิกข้อผิดพลาด
เกล็นแจ็คแมน

1
mcd เป็นคำสั่งที่มีอยู่แล้ว แม้ว่าคุณเพิ่งได้รับตัวอย่าง แต่ฉันใช้ตัวเองเพราะมันเป็นตัวอักษรที่สั้นกว่า mkcd
Dharmit

@Dharmit Shah: mcdคำสั่งที่มีอยู่คืออะไร? แพคเกจหรือโครงการใดให้คำสั่งนี้
มิเคล

2
mtools จัดเตรียมคำสั่ง mcd หน้าคนของมันบอกว่า "คำสั่ง mcd ใช้เพื่อเปลี่ยนไดเรกทอรีการทำงานของ mtools บนดิสก์ MS-DOS"
Dharmit

13

ถ้าคุณใช้ Oh My zsh มีคำสั่งเรียกใช้ที่ไม่ตรงนี้ มันจะมีลักษณะเช่นนี้

take myfolder

ฉันเจออันนี้โดยบังเอิญ ฉันเพิ่งดูและมันถูกระบุไว้ในสูตรโกงนี้จากวิกิโอ้ Oh My Zsh GitHub มันค่อนข้างจะเป็นคำสั่งที่มีประโยชน์และดูเหมือนจะสร้างตัวเองได้ง่ายมาก


1
ฉันไม่เคยรู้เลยtake:) สมบูรณ์แบบ! btw - iTerm2 กับ Oh My Zsh จริงๆแล้วมี 3 คำตอบที่สมบูรณ์แบบที่นี่ อันนี้อันนี้โดย @ jesús-carrera และคำตอบที่เลือก ขึ้นอยู่กับการตั้งค่าและการตั้งค่าของคุณ
ลุย

3

หรือคุณเพียงแค่สร้างตัวแปรสั้น ๆ แบบทันทีและใช้มันสองครั้งx = longproject ; mkdir $x ; cd $x- ซึ่งฉันยอมรับว่ายังใช้งานได้นานกว่าการใช้ฟังก์ชัน shellscript :)


0

นี่คือตัวแปรที่ควรพูดถึง:

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

เพิ่มสิ่งนี้ลงในของ~/.bash_profileคุณแล้วคุณสามารถใช้งานได้mkdirตามปกติ (เมื่อคุณใช้งานแล้วsource) ยกเว้นตอนนี้มันจะเรียกใช้ฟังก์ชันด้านบนแทนmkdirคำสั่งมาตรฐาน

หมายเหตุสิ่งนี้ไม่ได้ตรวจสอบความถูกต้องของอินพุตตามคำตอบที่ยอมรับโดย Gillesแต่แสดงให้เห็นว่าคุณสามารถแทนที่ builtins ได้อย่างไร (อย่างมีประสิทธิภาพ)

จากเอกสาร (การถอดความเล็กน้อย):

command mkdir [args]ทำงานmkdirกับไม่สนใจฟังก์ชั่นเชลล์ชื่อargs mkdirคำสั่ง shell builtin เท่านั้นหรือคำสั่งที่พบโดยการค้นหา PATH จะถูกดำเนินการ หากมีชื่อฟังก์ชั่นของเชลล์การlsเรียกใช้command lsภายในฟังก์ชั่นจะดำเนินการคำสั่งภายนอกlsแทนการเรียกใช้ฟังก์ชันซ้ำ

ผมเชื่อว่าประสบความสำเร็จในผลคล้ายกับbuiltincommand


คุณควรพูดอย่างแน่นอน$dir
Jeff Schaller

@ เจฟฟ์เห็นด้วย แต่คำตอบที่ยอมรับมีการตรวจสอบความถูกต้องครบถ้วน ฉันแค่นำเสนอการใช้commandเป็นทางเลือก
Arj

0

การเพิ่มฟังก์ชั่นตัวช่วยใน BASH, ZSH หรือ KSH

สร้างmkcdคำสั่งให้กับสภาพแวดล้อมของคุณในหนึ่งบรรทัด

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


-1

เพียงแค่ตอบคำถามข้างต้นโดยอัตโนมัติและสร้างสคริปต์ที่ใช้งานได้หนึ่งครั้ง:

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

echo "$fun" >> ~/.bashrc

เพียงคัดลอกในไฟล์ใหม่mkcd.shและเรียกใช้เพียงครั้งเดียวใน terminal bash mkcd.shโดย จากนั้นดำเนินการsource ~/.bashrcเพื่อให้ทำงานในเซสชันปัจจุบัน

หลังจากนี้คุณสามารถใช้mkcd some_dirเพื่อสร้างและป้อนโดยตรงในไดเรกทอรีนั้น


คุณแนะนำให้เขียนสคริปต์ (เป็นไฟล์) ซึ่งมีจุดประสงค์เพื่อต่อท้าย~/.bashrcไฟล์ (โดยมีคำตอบที่ได้รับไปแล้ว)? และคุณแนะนำให้สร้างmkcd.shสคริปต์นี้อย่างไร ด้วยเครื่องมือแก้ไขอาจ? ~/.bashrcนี้ดูเหมือนว่าการทำงานมากขึ้นกว่าเพียงแค่การแก้ไข สิ่งนี้มีประโยชน์อะไรมากกว่าคำตอบที่ยอมรับได้? …………………………………………………ทุก…………………………………ทุก ๆ สิ่งนี้จะล้มเหลวเนื่องจากปัญหาในการอ้างอิงซึ่งบอกได้ว่าคุณยังไม่ได้ลองด้วยตัวเอง
Scott

ฉันขอโทษที่จะพูด แต่ใช่เหมือนที่ฉันเขียนในคำตอบของฉันฉันใช้คำตอบข้างต้น มันใช้งานได้ดี ถ้าคุณไม่เชื่อฉันลองดูสิ และเกี่ยวกับการไม่พยายามฉันใช้เวลาทั้งวันเพื่อเขียนสคริปต์ใน bash และ python วันนี้
subtleseeker

ฉันลองสิ่งที่คุณเขียน มันไม่ทำงาน
สกอตต์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.