Unix - criar caminho de pastas e arquivos


125

Eu sei que você pode fazer mkdirpara criar um diretório e touchcriar um arquivo, mas não há como fazer as duas operações de uma só vez?

ou seja, se eu quiser fazer o abaixo quando a pasta othernão existir:

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

Erro:

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

Alguém veio com uma função como solução alternativa para isso?



Se for essencial que a criação do arquivo e seu diretório sejam atômicos, você precisará escrever um sistema de arquivos que ofereça essa operação. Não é possível com os sistemas de arquivos Linux padrão.
Peter G.

@topo Entendo que essa pergunta já está com um ano e meio de idade, mas várias respostas foram mescladas recentemente. Se você precisar desse tipo de coisa com muita frequência, poderá achar minha resposta útil. (Eu diria mais útil do que a resposta aceita, mas eu não estou implorando por rep aqui :-))
Jonathon Reinhart


@tdammers P: "Como eu faço o X?" A: "Veja como fazer Y"
Henry Henrinson

Respostas:


139

Use &&para combinar dois comandos em uma linha de shell:

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

Nota: Anteriormente, eu recomendei o uso de ;para separar os dois comandos, mas, como apontado pelo @trysis, provavelmente é melhor usar &&na maioria das situações, pois, caso as COMMAND1falhas COMMAND2também não sejam executadas. Caso contrário, isso pode levar a problemas que você não esperava.


16
Provavelmente é melhor usar &&, assim como ;se o primeiro comando falhar, o segundo comando ainda será executado (e falhará também, pois esse diretório ainda não existe). Com &&se o primeiro comando falhar, o segundo comando não será executado.
trysis

12
Um atalho para o exemplo de código pode ser: mkdir -p /my/other/path/here && touch $_/cpredthing.txt. O $_expande para essencialmente o "último argumento no último comando executado".
perfil completo de Sgnl

4
O @Sgnl é sem dúvida a resposta correta. Não é apenas mais limpo, é menos propenso a erros.
precisa saber é o seguinte

3
Eu realmente gostaria de touchter um -pparâmetro como mkdirfaz.
211719 Ben174

86

Você precisa criar todos os diretórios principais primeiro.

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

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

Se você deseja ser criativo, pode fazer uma função :

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

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

E então use-o como qualquer outro comando:

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

Mudou para usar &&- Como é isso?
Jonathon Reinhart 10/10

1
@ Bћовић Sim . (Eu tento coisas teste antes de publicá-las.)
Jonathon Reinhart

2
@JonathonReinhart Tem certeza de que o testou? Eu tentei supertouch "/tmp/abc/def ghi/jkl mno.txt"e falhou. Todos os comandos dirname, mkdire touchdeu Erros.
devnull

2
@ devnull Aparentemente, não está bem o suficiente. Condene seus espaços :-) Corrigido.
Jonathon Reinhart 10/10

1
@JeremyIglehart Eu gosto. mktouchisto é.
Jonathon Reinhart 30/03

24

Faça isso com / usr / bin / install:

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

quando você não possui um arquivo de origem:

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

1
Estou surpreso que essa ferramenta seja amplamente ignorada - o man install - mostrará que a instalação é uma solução melhor.
SC-SL

1
Você também pode usar -D /dev/null, o que é mais fácil para mim lembrar.
29618 wisbucky

14

Isto é o que eu faria:

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

Aqui, $_é uma variável que representa o último argumento para o comando anterior que executamos em linha.

Como sempre, se você quiser ver qual será a saída, pode testá-la usando o echocomando, da seguinte maneira:

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

Que gera como:

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

Como bônus, você pode gravar vários arquivos ao mesmo tempo usando a expansão entre chaves, por exemplo:

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

Novamente, totalmente testável com 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
Um usuário anônimo sugeriu (por meio de edição) para usar dirname -z "$@" | xargs -0 mkdir -p, pelo bem do desempenho. (Stop à espreita, e juntar-se, pelo amor de Pete ;-)!
jpaugh

11

você pode fazer isso em duas etapas:

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

como eu vi e testei em um fórum unix, isso resolve o problema

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

1

não há necessidade de if thendeclarações ... você pode fazê-lo em uma única linha;

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

- ou em duas linhas -

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

- o -perro impede que retorne se o diretório já existir (que é o que eu vim aqui procurando :))


1

No caso especial (mas não incomum) em que você está tentando recriar a mesma hierarquia de diretórios, cp --parentspode ser útil.

Por exemplo, se /my/longcontém os arquivos de origem e my/otherjá existe, você pode fazer isso:

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

-4

se você quiser simples com apenas 1 snippet de parâmetro:

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
Se você quiser simplesmente se livrar das últimas horas de trabalho, jogue gratamente alguns rm -rfcomandos. - † Ou seja, horas , desde que você adote uma política de controle / backup de versão sensata ... caso contrário, pode levar meses.
leftaroundabout

1
rm -rfnunca deve ser sugerido sem explicações e avisos adequados.
Mausy5043
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.