Unix - สร้างเส้นทางของโฟลเดอร์และไฟล์


126

ฉันรู้ว่าคุณสามารถmkdirสร้างไดเร็กทอรีและtouchสร้างไฟล์ได้ แต่ไม่มีวิธีใดที่จะดำเนินการทั้งสองอย่างในคราวเดียวได้?

เช่นถ้าฉันต้องการทำด้านล่างเมื่อotherไม่มีโฟลเดอร์:

cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

ข้อผิดพลาด:

cp: cannot create regular file `/my/other/path/here/cpedthing.txt': No such file or directory

มีใครคิดฟังก์ชันเป็นวิธีแก้ปัญหานี้หรือไม่?



หากจำเป็นอย่างยิ่งที่การสร้างไฟล์และไดเร็กทอรีเป็นแบบอะตอมคุณจะต้องเขียนระบบไฟล์ที่มีการดำเนินการนี้ เป็นไปไม่ได้กับระบบไฟล์ Linux มาตรฐาน
Peter G.

@toop ฉันเข้าใจว่าตอนนี้คำถามนี้มีอายุหนึ่งปีครึ่งแล้ว แต่เมื่อไม่นานมานี้มีคำตอบหลายคำตอบรวมเข้าด้วยกัน หากคุณต้องการสิ่งนี้บ่อย ๆ คุณอาจพบว่าคำตอบของฉันมีประโยชน์ (ฉันจะเถียงว่ามีประโยชน์มากกว่าคำตอบที่ยอมรับ แต่ฉันไม่ได้ขอตัวแทนที่นี่ :-))
Jonathon Reinhart

พบสิ่งนี้: stackoverflow.com/a/8722721/29182
Ziggy

@tdammers ถาม: "ฉันจะ X ได้อย่างไร" A: "นี่คือวิธีการทำ Y"
Henry Henrinson

คำตอบ:


140

ใช้&&เพื่อรวมสองคำสั่งในหนึ่งเชลล์บรรทัด:

COMMAND1 && COMMAND2
mkdir -p /my/other/path/here/ && touch /my/other/path/here/cpedthing.txt

หมายเหตุ: ก่อนหน้านี้ฉันแนะนำให้ใช้;เพื่อแยกสองคำสั่ง แต่ตามที่ @trysis ชี้ไว้น่าจะดีกว่าที่จะใช้&&ในสถานการณ์ส่วนใหญ่เพราะในกรณีที่COMMAND1ล้มเหลวCOMMAND2จะไม่ถูกดำเนินการเช่นกัน (มิฉะนั้นอาจนำไปสู่ปัญหาที่คุณอาจไม่คาดคิด)


16
อาจจะดีกว่าที่จะใช้&&เช่นเดียวกับ;หากคำสั่งแรกล้มเหลวคำสั่งที่สองจะยังคงทำงานอยู่ (และล้มเหลวเช่นกันเนื่องจากยังไม่มีไดเร็กทอรีนั้น) ด้วย&&ถ้าคำสั่งแรกล้มเหลวคำสั่งที่สองไม่ทำงาน
trysis

12
ตัวอย่างโค้ดสั้น ๆ คือ: mkdir -p /my/other/path/here && touch $_/cpredthing.txt. ส่วน$_ขยายเป็น "อาร์กิวเมนต์สุดท้ายในคำสั่งสุดท้ายที่ดำเนินการ"
Sgnl

4
@Sgnl ของคุณเป็นคำตอบที่ถูกต้อง ไม่ใช่แค่สะอาดกว่า แต่ยังเกิดข้อผิดพลาดน้อยกว่า
Choylton B. Higginbottom

3
ฉันหวังว่าจะtouchใช้-pพารามิเตอร์เช่นmkdirนี้
Ben174

86

คุณต้องสร้างไดเร็กทอรีหลักทั้งหมดก่อน

FILE=./base/data/sounds/effects/camera_click.ogg

mkdir -p "$(dirname "$FILE")" && touch "$FILE"

หากคุณต้องการสร้างสรรค์คุณสามารถสร้างฟังก์ชัน :

mktouch() {
    if [ $# -lt 1 ]; then
        echo "Missing argument";
        return 1;
    fi

    for f in "$@"; do
        mkdir -p -- "$(dirname -- "$f")"
        touch -- "$f"
    done
}

จากนั้นใช้มันเหมือนกับคำสั่งอื่น ๆ :

mktouch ./base/data/sounds/effects/camera_click.ogg ./some/other/file

เปลี่ยนมาใช้&&- เป็นอย่างไรบ้าง?
Jonathon Reinhart

1
@ BЈовић ใช่ (ฉันพยายามทดสอบก่อนโพสต์)
Jonathon Reinhart

2
@JonathonReinhart แน่ใจนะว่าทดสอบแล้ว? ฉันพยายามsupertouch "/tmp/abc/def ghi/jkl mno.txt"แล้วมันล้มเหลว คำสั่งทั้งหมดdirname, mkdirและtouchให้ erros
devnull

2
@devnull เห็นได้ชัดว่ายังไม่ดีพอ แก้ไขช่องว่างของคุณ :-)
Jonathon Reinhart

1
@JeremyIglehart ชอบค่ะ mktouchมันคือ.
Jonathon Reinhart

24

ทำได้ด้วย / usr / bin / install:

install -D /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

เมื่อคุณไม่มีไฟล์ต้นฉบับ:

install -D <(echo 1) /my/other/path/here/cpedthing.txt

1
ฉันรู้สึกประหลาดใจที่เครื่องมืออัญมณีนี้ถูกละเลยโดยส่วนใหญ่ - การติดตั้งโดยคน - จะแสดงให้เห็นว่าการติดตั้งเป็นทางออกที่ดีกว่า
SC-SL

1
คุณยังสามารถใช้-D /dev/nullซึ่งง่ายกว่าสำหรับฉันที่จะจำ
wisbucky

14

นี่คือสิ่งที่ฉันจะทำ:

mkdir -p /my/other/path/here && touch $_/cpredthing.txt

นี่$_คือตัวแปรที่แสดงถึงอาร์กิวเมนต์สุดท้ายของคำสั่งก่อนหน้าที่เราดำเนินการในบรรทัด

เช่นเคยหากคุณต้องการดูว่าผลลัพธ์เป็นอย่างไรคุณสามารถทดสอบได้โดยใช้echoคำสั่งดังนี้:

echo mkdir -p /code/temp/other/path/here && echo touch $_/cpredthing.txt

ซึ่งผลลัพธ์เป็น:

mkdir -p /code/temp/other/path/here
touch /code/temp/other/path/here/cpredthing.txt

เป็นโบนัสคุณสามารถเขียนหลายไฟล์พร้อมกันโดยใช้การขยายวงเล็บปีกกาตัวอย่างเช่น:

mkdir -p /code/temp/other/path/here &&
touch $_/{cpredthing.txt,anotherfile,somescript.sh}

อีกครั้งทดสอบได้ทั้งหมดด้วยecho:

mkdir -p /code/temp/other/path/here
touch /code/temp/other/path/here/cpredthing.txt /code/temp/other/path/here/anotherfile /code/temp/other/path/here/somescript.sh

13
#!/bin/sh
for f in "$@"; do mkdir -p "$(dirname "$f")"; done
touch "$@"

1
ผู้ใช้ที่ไม่ระบุชื่อแนะนำ (ผ่านการแก้ไข) ให้ใช้dirname -z "$@" | xargs -0 mkdir -pแทนเพื่อประสิทธิภาพ (หยุดซุ่ม
โจมตี



2

ตามที่ฉันเห็นและทดสอบในฟอรัม Unix สิ่งนี้ช่วยแก้ปัญหาได้

ptouch() {
    for p in "$@"; do
        _dir="$(dirname -- "$p")"
        [ -d "$_dir" ] || mkdir -p -- "$_dir"
    touch -- "$p"
    done
}

1

ไม่ต้องใช้if thenงบ ... คุณสามารถทำได้ด้วยการใช้บรรทัดเดียว;

mkdir -p /my/other/path/here;cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

- หรือสองบรรทัด -

mkdir -p /my/other/path/here
cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt

- การ-pป้องกันข้อผิดพลาดจะส่งคืนหากมีไดเร็กทอรีอยู่แล้ว (ซึ่งเป็นสิ่งที่ฉันมาที่นี่เพื่อค้นหา :))


1

ในกรณีพิเศษ (แต่ไม่ใช่เรื่องผิดปกติ) ที่คุณพยายามสร้างลำดับชั้นของไดเร็กทอรีเดียวกันใหม่cp --parentsอาจมีประโยชน์

ตัวอย่างเช่นหาก/my/longมีไฟล์ต้นฉบับและmy/otherมีอยู่แล้วคุณสามารถทำได้:

cd /my/long
cp --parents path/here/thing.txt /my/other

-4

หากคุณต้องการความเรียบง่ายโดยมีเพียงตัวอย่างพารามิเตอร์ 1 รายการ:

rm -rf /abs/path/to/file;  #prevent cases when old file was a folder
mkdir -p /abs/path/to/file; #make it fist as a dir
rm -rf /abs/path/to/file; #remove the leaf of the dir preserving parents 
touch /abs/path/to/file; #create the actual file

3
หากคุณต้องการกำจัดงานในช่วงสองสามชั่วโมงที่ผ่านมาให้ใช้rm -rfคำสั่งบางอย่างโดยไม่เต็มใจ - †นั่นคือชั่วโมงโดยสมมติว่าคุณปฏิบัติตามนโยบายการควบคุม / สำรองข้อมูลเวอร์ชันที่เหมาะสม ... มิฉะนั้นอาจเป็นเดือน
leftaround ประมาณ

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