Unix - tạo đường dẫn của thư mục và tệp


125

Tôi biết bạn có thể làm mkdirđể tạo một thư mục và touchtạo một tệp, nhưng không có cách nào để thực hiện cả hai thao tác trong một lần?

tức là nếu tôi muốn làm như dưới đây khi thư mục otherkhông tồn tại:

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

Lỗi:

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

Có ai đã đưa ra một chức năng như một cách giải quyết cho điều này?


1
Tìm thấy cái này: stackoverflow.com/questions/1529946/
Mạnh

Nếu điều cần thiết là việc tạo tệp và thư mục của nó là nguyên tử, bạn sẽ phải viết một hệ thống tệp cung cấp thao tác này. Không thể với các hệ thống tệp Linux tiêu chuẩn.
Peter G.

@toop Tôi hiểu rằng câu hỏi này đã được một năm rưỡi, nhưng một số câu trả lời gần đây đã được hợp nhất vào câu hỏi này. Nếu bạn cần loại điều này rất thường xuyên, bạn có thể thấy câu trả lời của tôi hữu ích. (Tôi tranh luận hữu ích hơn câu trả lời được chấp nhận, nhưng tôi không cầu xin đại diện ở đây :-))
Jonathon Reinhart

Tìm thấy cái này: stackoverflow.com/a/8722721/29182
Ziggy

@tdammers Q: "Làm thế nào để tôi làm X?" A: "Đây là cách làm Y"
Henry Henrinson

Câu trả lời:


139

Sử dụng &&để kết hợp hai lệnh trong một dòng shell:

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

Lưu ý: Trước đây tôi đã khuyến nghị sử dụng ;để tách hai lệnh nhưng như được chỉ ra bởi @trysis, có lẽ tốt hơn nên sử dụng &&trong hầu hết các tình huống vì trong trường hợp COMMAND1không thành công COMMAND2sẽ không được thực thi. (Nếu không, điều này có thể dẫn đến các vấn đề bạn có thể không mong đợi.)


16
Có lẽ tốt hơn để sử dụng &&, như với ;, nếu lệnh đầu tiên thất bại, lệnh thứ hai vẫn sẽ chạy (và thất bại, vì thư mục đó chưa tồn tại). Với &&nếu lệnh đầu tiên thất bại, lệnh thứ hai không chạy.
phân chia

12
Một cắt ngắn cho ví dụ mã có thể là : mkdir -p /my/other/path/here && touch $_/cpredthing.txt. Việc $_mở rộng về cơ bản là "đối số cuối cùng trong lệnh cuối cùng được thực thi".
Sgnl

4
@Sgnl của bạn được cho là câu trả lời chính xác. Nó không chỉ sạch hơn, ít bị lỗi hơn.
Choylton B. Higginbottom

3
Tôi thực sự muốn touchlấy một -ptham số như mkdirkhông.
Ben174

86

Bạn cần phải làm cho tất cả các thư mục cha mẹ đầu tiên.

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

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

Nếu bạn muốn sáng tạo, bạn có thể tạo một chức năng :

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

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

Và sau đó sử dụng nó như bất kỳ lệnh nào khác:

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

Thay đổi nó để sử dụng &&- Làm thế nào?
Jonathon Reinhart

1
@ BЈовић . (Tôi cố gắng kiểm tra mọi thứ trước khi đăng chúng.)
Jonathon Reinhart

2
@JonathonReinhart Bạn có chắc chắn rằng bạn đã thử nghiệm nó? Tôi đã thử supertouch "/tmp/abc/def ghi/jkl mno.txt"và nó đã thất bại. Tất cả các lệnh dirname, mkdirtouchđã đưa ra erros.
devnull

2
@devnull Rõ ràng là không đủ tốt. Chết tiệt không gian của bạn :-) Đã sửa.
Jonathon Reinhart

1
@JeremyIglehart Tôi thích nó. mktouchnó là.
Jonathon Reinhart

24

Làm điều đó với / usr / bin / install:

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

khi bạn không có tệp nguồn:

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

1
Tôi ngạc nhiên công cụ đá quý này phần lớn bị bỏ qua - man install - sẽ cho thấy rằng cài đặt là một giải pháp tốt hơn.
SC-SL

1
Bạn cũng có thể sử dụng -D /dev/null, nó dễ nhớ hơn đối với tôi.
wvducky

14

Đây là những gì tôi sẽ làm:

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

Ở đây, $_là một biến đại diện cho đối số cuối cùng cho lệnh trước đó mà chúng ta đã thực hiện trong dòng.

Như mọi khi nếu bạn muốn xem đầu ra có thể là gì, bạn có thể kiểm tra nó bằng cách sử dụng echolệnh, như vậy:

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

Đầu ra nào là:

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

Như một phần thưởng, bạn có thể viết nhiều tệp cùng một lúc bằng cách sử dụng mở rộng dấu ngoặc, ví dụ:

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

Một lần nữa, hoàn toàn có thể kiểm tra với 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 -pThay vào đó, một người dùng ẩn danh đã đề xuất (thông qua chỉnh sửa) để sử dụng vì mục đích hiệu suất. (Dừng ẩn nấp và tham gia, vì lợi ích của Pete! ;-)
jpaugh

11

bạn có thể làm điều đó theo hai bước:

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

2
if [ ! -d /my/other ]
then
   mkdir /my/other/path/here
   cp /my/long/path/here/thing.txt /my/other/path/here/cpedthing.txt
fi

2

như tôi đã thấy và kiểm tra trong một diễn đàn unix, điều này giải quyết vấn đề

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

1

không cần if thenbáo cáo ... bạn có thể làm điều đó trên một dòng đơn;

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

- hoặc trên hai dòng -

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

- -pngăn lỗi trả về nếu thư mục đã tồn tại (đó là những gì tôi đến đây để tìm :))


1

Trong trường hợp đặc biệt (nhưng không phổ biến) khi bạn đang cố gắng tạo lại hệ thống phân cấp thư mục tương tự, cp --parents có thể hữu ích.

Ví dụ: nếu /my/longchứa các tệp nguồn và my/otherđã tồn tại, bạn có thể làm điều này:

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

-4

nếu bạn muốn đơn giản chỉ với 1 đoạn trích param:

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
Nếu bạn chỉ muốn thoát khỏi công việc trong vài giờ qua, hãy ném một cách hài lòng xung quanh một số rm -rflệnh. - Nghĩa là hàng giờ , giả sử bạn tuân thủ chính sách kiểm soát / sao lưu phiên bản hợp lý ... nếu không, đó có thể là tháng.
leftaroundabout

1
rm -rfkhông bao giờ nên được đề xuất mà không có lời giải thích và cảnh báo thích hợp.
Mausy5043
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.