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

Кто-нибудь придумал функцию как обходной путь для этого?

Toop
источник
1
Нашел это: stackoverflow.com/questions/1529946/…
Bjørne Malmanger
Если важно, чтобы создание файла и его каталога было атомарным, вам нужно будет написать файловую систему, которая предлагает эту операцию. Это невозможно со стандартными файловыми системами Linux.
Питер Г.
@toop Я понимаю, что этому вопросу уже полтора года, но недавно в него было объединено несколько ответов. Если вам нужны такие вещи очень часто, мой ответ может быть вам полезен. (Я бы сказал, более полезен, чем принятый ответ, но я не прошу здесь репутации :-))
Джонатон Рейнхарт
Нашел это: stackoverflow.com/a/8722721/29182
Зигги
@tdammers Q: "Как мне сделать X?" A: «Вот как сделать Y»
Генри Хенринсон

Ответы:

140

Используйте &&для объединения двух команд в одной строке оболочки:

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

Примечание: ранее я рекомендовал использовать ;для разделения двух команд, но, как указано в @trysis, вероятно, лучше использовать &&в большинстве ситуаций, потому что в случае COMMAND1сбоя COMMAND2также не будет выполняться. (В противном случае это может привести к проблемам, которых вы, возможно, не ожидали.)

evotopid
источник
16
Вероятно, лучше использовать &&, как ;и в случае, если первая команда не удалась, вторая команда все равно будет выполняться (и тоже не удастся, поскольку этот каталог еще не существует). С , &&если первая команда терпит неудачу, вторая команда не выполняется.
trysis
12
Короткий срез для примера кода может быть: mkdir -p /my/other/path/here && touch $_/cpredthing.txt. В $_раскрываться по существу «последнему аргументу в последней выполненной команде».
Sgnl
4
@Sgnl, возможно, ваш правильный ответ. Он не просто чище, он менее подвержен ошибкам.
Чойлтон Б. Хиггинботтом
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
Джонатон Рейнхарт
источник
Поменял на использование &&- Как это?
Джонатон Рейнхарт,
1
@ BЈовић Да . (Я действительно пытаюсь протестировать вещи, прежде чем размещать их.)
Джонатон Рейнхарт
2
@JonathonReinhart Вы уверены, что тестировали? Я попробовал, supertouch "/tmp/abc/def ghi/jkl mno.txt"но ничего не вышло. Все команды dirname, mkdirи touchдали erros.
devnull
2
@devnull По-видимому, недостаточно хорошо. К черту ваши пробелы :-) Исправлено.
Джонатон Рейнхарт
1
@JeremyIglehart Мне это нравится. mktouchэто.
Джонатон Рейнхарт,
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вместо этого для повышения производительности. (Прекратите прятаться и присоединяйтесь, ради Пита! ;-)
jpaugh
11

вы можете сделать это в два этапа:

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

как я видел и тестировал на форуме unix, это решает проблему

ptouch() {
    for p in "$@"; do
        _dir="$(dirname -- "$p")"
        [ -d "$_dir" ] || mkdir -p -- "$_dir"
    touch -- "$p"
    done
}
Фабиан Риос
источник
1

нет необходимости в if thenутверждениях ... вы можете сделать это в одной строке usign;

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ошибка предотвращения возвращается, если каталог уже существует (это то, что я здесь искал :))

tediffer3rd
источник
1

В особом (но не редком) случае, когда вы пытаетесь воссоздать ту же иерархию каталогов, это cp --parentsможет быть полезно.

Например, если он /my/longсодержит исходные файлы и my/otherуже существует, вы можете сделать это:

cd /my/long
cp --parents path/here/thing.txt /my/other
Тодд Оуэн
источник
-4

если вам нужен простой фрагмент с одним параметром:

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команд. - † То есть часы , если вы придерживаетесь разумной политики управления версиями / резервного копирования ... в противном случае это могут быть месяцы.
уехал примерно
1
rm -rfникогда не следует предлагать без надлежащих объяснений и предупреждений.
Mausy5043