mkdir -p para arquivos

24

mkdir -pcriará um diretório; também criará diretórios pai, conforme necessário.

Existe um comando semelhante para arquivos, que criará um arquivo e diretórios pai, conforme necessário?

Steven Penny
fonte
Não que eu saiba .. mas você pode simplesmente executar mkdir -p / caminho / para / make && toque / caminho / para / arquivo ... O que tornaria um arquivo vazio nessa nova estrutura de diretórios que você criou tudo conforme necessário.
1
@Kansha que combinam com dirnamee basename, e nós só vai precisar do único argumento; lucro! :)
Sim, boa ligação.

Respostas:

29

A instalação fará isso, se for fornecido o arquivo de origem /dev/null. O -Dargumento diz para criar todos os diretórios pai:

anthony@Zia:~$ install -D /dev/null /tmp/a/b/c
anthony@Zia:~$ ls -l /tmp/a/b/c 
-rwxr-xr-x 1 anthony anthony 0 Jan 30 10:31 /tmp/a/b/c

Não tenho certeza se isso é um bug ou não - seu comportamento com os arquivos do dispositivo não é mencionado na página de manual. Você também pode fornecer um arquivo em branco (recém-criado mktemp, por exemplo) como fonte.

derobert
fonte
7

Não, não é tanto quanto eu sei. Mas você sempre pode usar mkdir -pe touchdepois um do outro:

f="/a/b/c.txt"
mkdir -p -- "${f%/*}" && touch -- "$f"
ldx
fonte
3

Frequentemente me deparei com esse tipo de situação, então simplesmente escrevi uma função no meu .bashrcarquivo. Se parece com isso

function create() {
    arg=$1
    num_of_dirs=$(grep -o "/" <<< $arg | wc -l)
    make_dirs=$(echo $arg | cut -d / -f1-$num_of_dirs)
    mkdir -p $make_dirs && touch $arg
}

Então, quando eu quiser criar um arquivo dentro de um caminho de diretórios inexistentes, direi

create what/is/it  # will create dirs 'what' and 'is', with file 'it' inside 'is'
ViKiG
fonte
1
Meu homem! - obrigado, eu chamei isso touchp, tipomkdir -p
ecoologic
0
dir=$(dirname "$f")
test -d $dir || mkdir -p "$dir"
Yordan Georgiev
fonte
3
O testnão é necessário; mkdir -pnão faz nada se o dir já existe. Nem retorna um erro.
derobert
1
E, claro, isso apenas cria o diretório.
um CVn 30/01
0

Eu sugeriria, pois a mantém em uma linha, embora definir a variável separadamente permita alterá-la e executar novamente o comando do histórico com bastante facilidade.

B="./make/this/path" && mkdir -p -- "$B" && touch -- "$B/file.txt"
Gilles 'SO- parar de ser mau'
fonte
0

É possível "fingir".

Primeiro, alguma teoria necessária:

Rob Griffiths publicou um artigo em 2007 intitulado Crie facilmente muitas novas pastas no Macworld.com, no qual ele discutiu o uso do xargscomando para ler uma lista de arquivos para criar diretórios usando mkdir.

xargsé capaz de referenciar a placeholder( {}) com o -Isinalizador, que contém o valor de cada argumento passado para xargs. Aqui está a diferença entre com essa bandeira e sem:

$ foo.txt bar.txt | xargs echo
$ => foo.txt bar.txt
$ foo.txt bar.txt | xargs -I {} echo {}
$ => foo.txt
$ => bar.txt

xargstambém é capaz de executar comandos arbitrários do shell com o sh -csinalizador:

foo.txt bar.txt | xargs sh -c 'echo arbitrary command!'

Combinando os conceitos:

Podemos combinar estes conceitos com mkdir -p, em vez de mkdire o conceito em @ldx 's resposta para produzir este:

$ cat files.txt | xargs -I {} sh -c 'f="{}" && mkdir -p -- "${f%/*}" && touch -- "$f"'

Esse comando basicamente mapeia cada nome de arquivo em uma lista de arquivos separados por linha, corta a parte do arquivo, cria os diretórios com mkdir -pe, em seguida, touches o nome do arquivo em seu respectivo diretório.

Aqui está um detalhamento do que acontece no comando acima:

Digamos, por exemplo, minha files.txtaparência assim:

deeply/nested/foo/bar.txt
deeply/nested/baz/fiz.txt
  • cat files.txt produz deeply/nested/foo/bar.js deeply/nested/baz/fiz.txt
  • deeply/nested/foo/bar.js deeply/nested/baz/fiz.txt é canalizado para xargs
  • porque usamos -I {}, xargstraduziremos cada argumento para seu próprio comando, então agora temos:
    • deeply/nested/foo/bar.txt
    • deeply/nested/baz/fiz.txt
  • em seguida, executamos um comando shell que usa o &&combinador para agrupar 3 comandos que são executados seqüencialmente - o primeiro comando armazena o arquivo em uma variável de ambiente (que é reutilizada na próxima passagem de arquivo) usando o espaço reservado que registramos antes, então agora ter:
    • f=deeply/nested/foo/bar.txt
    • f=deeply/nested/baz/fiz.txt
  • agora temos uma variável para a qual podemos passar mkdir -p, mas precisamos cortar o nome do arquivo. Simples o suficiente usando '${f%/*}':
    • mkdir -p deeply/nested/foo/
    • mkdir -p deeply/nested/baz/
  • e então apenas referenciamos a fvariável na sua totalidade quando touch:
    • touch deeply/nested/foo/bar.txt
    • touch deeply/nested/baz/fiz.txt
razorbeard
fonte
2
Você tem toda essa explicação para o que é, essencialmente cat files.txt | xargs -I {} sh -c 'f="{}" && mkdir -p -- "${f%/*}" && touch -- "$f"', que tem UUOC, então você subnível para xargs que subshells volta para o shell, quando um while readciclo faz mais sentido
Steven Penny
1
Admito que não sou o mais informado sobre os comandos * nix - nem sei o que é o UUOC -, mas não vejo como essa é uma resposta terrível. É pesquisado, testado e é uma solução funcional para sua pergunta original. É construtivo (ao contrário do seu comentário bastante rude). Por favor, se você achar que eu fiz algo irresponsável aqui que não deveria, faça mais explicações - explique o porquê . Não me importo muito com debates opinativos sem substância.
Razorbeard
1
Meu último comentário explica perfeitamente. Toda a sua resposta poderia ser melhor escrita como while read f; do mkdir -p "$(dirname "$f")"; touch "$f"; done < files.txt. O fato de que você não pode fazer uma pesquisa 10 segundo internet para UUOC também está dizendo
Steven Penny