ฉันจะดำเนินการคำสั่งในโฟลเดอร์อื่นโดยไม่ต้องทำเส้นทางโฟลเดอร์ซ้ำได้อย่างไร


73

มีวิธีที่ชาญฉลาดในการทำสำเนาและย้ายการดำเนินการหรือคำสั่งเพื่อทำซ้ำไฟล์โดยไม่ต้องทำ a หลังจากcdนั้นmvในโฟลเดอร์เดียวกันหรือไม่?

ตัวอย่างเช่นฉันต้องเรียกใช้ต่อไปนี้:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

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


9
ฉันไม่อยากจะเชื่อเลยว่ามี upvotes มากมาย มันคือunix.stackexchange.com/questions/35782/…ที่ซ้ำกันและunix.stackexchange.com/questions/66889/…
user13107

13
@ user13107 มีหลายวิธีในการถามคำถามรวมถึงการใช้ถ้อยคำที่แตกต่างกัน และถ้าคุณไม่รู้ว่าคำตอบนั้นเรียกว่า "การขยายรั้ง" คุณอาจไม่สามารถค้นหาได้ทันที
slhck

2
@ user13107 พวกเขาอยู่ในเว็บไซต์ที่แตกต่างกันดังนั้นจึงไม่ซ้ำกัน
user151019

1
ทำเครื่องหมายขอบคุณฉันไม่รู้กฎนั้นเกี่ยวกับการทำซ้ำ @slhck ใช่ ฉันเข้าใจ. ฉันรู้สึกผิดหวังเพราะคำถามของฉันเกี่ยวกับ Unix.SE ถูกปิดเหมือนซ้ำและคำถามนี้ได้รับความนิยมมาก
user13107

3
@ user13107 นั่นคือสิ่งที่คุณจะได้รับจากการโพสต์บนเว็บไซต์ที่ถูกต้อง
Samuel Edwin Ward

คำตอบ:


125

เพียงใช้การขยายรั้ง :

mv /folder1/folder2/folder3/{file.txt,file-2013.txt}

นี่เทียบเท่ากับการเขียน:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

รั้งการขยายตัวช่วยให้คุณสามารถจัดหาข้อโต้แย้งมากขึ้นแน่นอน คุณยังสามารถผ่านช่วงนั้นเช่นการสร้างคู่ของโฟลเดอร์ทดสอบคุณสามารถเรียกใช้mkdir test_{a..z}และเริ่มต้นด้วยการทุบตี 4 คุณสามารถสร้างลำดับศูนย์เบาะเป็นอย่างดีในขณะtouch foo{0001..3}ที่สร้างfoo0001, และfoo0002 ทุบตีแฮกเกอร์วิกิพีเดียมีบทความที่มีคู่ของตัวอย่างสำหรับคุณหนึ่งfoo0003

หากคุณมีการใช้สองคำสั่งที่แตกต่างกันใช้ subshell และcdมีครั้งแรกในขณะที่ @ คำตอบของอิกนาซิโอ


5
ฉันไม่รู้เกี่ยวกับการbraceขยายตัวขอบคุณ!
Valter Silva

ฉันพยายามแล้วและดูเหมือนว่าจะไม่ทำงาน:meniac ~: mv /tmp/f1/f2/f3/f4/f5/f6/{file.txt, file2.txt} mv: cannot stat ``/tmp/f1/f2/f3/f4/f5/f6/{file.txt,': No such file or directory
Valter Silva

5
คุณแน่ใจหรือไม่ว่าคุณกำลังใช้ Bash เช่นเดียวกับใน/bin/bashและคุณไม่ได้อยู่ในสคริปต์ที่มี/bin/shอยู่ใน shebang หรือเปลือกอื่น ๆ ที่ไม่สนับสนุนการขยายตัวของรั้ง? หากคุณทำงานsetไม่คุณSHELLOPTSมีbraceexpand?
slhck

22
โปรดทราบว่าควรจะมีไม่มีช่องว่างระหว่างและfile.txt, file2.txt
slhck

9
คุณสามารถทำให้สั้นยิ่งขึ้นเพื่อป้องกันการพิมพ์ผิดในส่วนที่ไม่เปลี่ยนแปลง:mv /folder1/folder2/folder3/file{,-2013}.txt
Jan Fabry

74

เรียกใช้การดำเนินการใน subshell

( cd /folder1/folder2/folder3 && mv file.txt file-2013.txt )

การเปลี่ยนแปลงของไดเรกทอรีทำงานจะไม่ถูกเผยแพร่ไปยังเปลือกหลัก


11
1: ผมชอบที่หนึ่งมากขึ้นหอยพกพาข้ามกว่าเคล็ดลับรั้งขยายตัว (ซึ่งเป็นระเบียบ แต่พกพาน้อยกว่า)
โอลิเวีย Dulac

@ Olivier สิ่งที่ทำให้คุณคิดว่าการขยายรั้งไม่พกพา? คุณมีกระสุนอยู่ในใจที่ไม่รองรับหรือไม่?
อเล็กซิส

5
@alexis การขยายรั้งไม่ได้ระบุไว้โดย POSIX ดังนั้นจึงไม่ใช่พกพา "โดยการออกแบบ" ash, dash, ksh88ไม่พูดถึงบอร์นเชลล์เก่าเป็นตัวอย่างของเปลือกหอยไม่สนับสนุนมัน
jlliagre

@jlliagre เชลล์ใดที่คุณกล่าวถึงเป็น POSIX ที่สอดคล้องกันอย่างสมบูรณ์ นั่นหมายความว่าพวกเขาจะไม่รั้งการขยายตัวแม้ว่าจะเป็น POSIX ksh88 เป็นก่อน POSIX ได้รับการยอมรับ; คุณควรอัพเกรดเป็น ksh93 เป็นอย่างน้อย มีเพียงคนสองคนใน Linux เท่านั้นที่สนใจคือเถ้าและเส้นประเนื่องจากถูกใช้ใน distros ขนาดเล็กบางส่วน (busybox, iirc?) และดิสก์กู้ชีพ
Kaz

2
@Kaz ฉันสนใจเกี่ยวกับการพกพาของคำสั่งเชลล์และความจริงที่พวกมันเป็นแบบโต้ตอบหรือไม่สำคัญ แน่นอนคุณมีอิสระที่จะไม่สนใจเรื่องนี้ แต่โปรดยอมรับว่าคนอื่นคิดเช่นนั้น ความจริงที่ว่าคุณใช้ bash หรือ shell ที่สนับสนุน barce-expansion เสมอไม่ได้หมายความว่าเป็นกรณีของทุกคน
jlliagre

21

หากคุณต้องการฉลาดนี่คือการขยายประวัติทุบตี

mv /folder1/folder2/folder3/file.txt !#:1:h/file-2013.txt

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


11

คุณสามารถตั้งค่าตัวแปร แน่นอนว่าสิ่งนี้มีผลข้างเคียงของการทิ้งตัวแปรไว้

D=/folder1/folder2/folder3; mv $D/file.txt $D/file-2013.txt

และแน่นอนคุณสามารถหลีกเลี่ยงผลข้างเคียงของการทิ้งตัวแปรไว้โดยใส่บรรทัดคำสั่งทั้งหมดลงใน subshell: (D="/folder1/folder2/folder3"; mv "$D"/file.txt "$D"/file-2013.txt)หรือเพียงแค่เพิ่มunsetคำสั่งที่ส่วนท้าย (ฉันเพิ่มเครื่องหมายคำพูดเป็น "แนวปฏิบัติที่ดีที่สุด" ถ้าคุณใช้คำพูดเสมอคุณจะไม่ต้องหยุดและเกาหัวเมื่อชื่อพา ธ ที่มีอักขระพิเศษมา)
Scott

@Scott หากคุณจะใช้ subshell เพื่อกำจัดผลข้างเคียงมันง่ายcdกว่าการตั้งค่าตัวแปร ไม่ได้เป็นจำนวนมากได้ง่ายขึ้นผมยอมรับ
Isaac Rabinovitch

2

ฉันชอบโซลูชันอื่น ๆ แต่นี่คืออีกวิธีหนึ่งที่ใช้เป็นสคริปต์ที่มี bash arrays, pushd, popd:

#!/bin/bash
set -e
# from http://stackoverflow.com/a/246128/178651
script_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# paths relative to the script
relative_paths=( \
path1 \
path2 \
path3 \
path4
)

for relative_path in "${relative_paths[@]}"
do
  pushd "$script_path/$relative_path" > /dev/null 2>&1
  pwd
  mv filename1 filename2
  # could do other stuff in this directory...
  popd > /dev/null 2>&1
done

pushd "$script_path" > /dev/null 2>&1
# could do other stuff in same directory as script...
popd > /dev/null 2>&1

1

Slhck ตอบคำถามโดยตรงในวิธีที่ง่ายที่สุด แต่ Valter ก็ชอบคำตอบ autopop ด้วยดังนั้นนี่คือคำถามที่อยู่ในแนวเดียวกัน

pushd /folder1/folder2/folder3/; mv file.txt file-2013.txt; popd
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.