mkdir -p para archivos

24

mkdir -pcreará un directorio; también creará directorios principales según sea necesario.

¿Existe un comando similar para los archivos, que creará un archivo y directorios principales según sea necesario?

Steven Penny
fuente
No es que yo sepa ... pero podrías hacer mkdir -p / path / to / make && touch / path / to / file ... Lo que haría un archivo vacío en esa nueva estructura de directorio que creaste todo lo necesario.
1
@Kansha combina eso con dirnamey basenamey solo necesitaremos el argumento único; ¡lucro! :)
Sí, buena llamada.

Respuestas:

29

Instalar hará esto, si se le da el archivo fuente /dev/null. El -Dargumento dice crear todos los directorios principales:

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

No estoy seguro de si eso es un error o no: su comportamiento con los archivos del dispositivo no se menciona en la página del manual. También podría simplemente darle un archivo en blanco (recién creado con mktemp, por ejemplo) como fuente.

derobert
fuente
7

No, no hasta donde yo sé. Pero siempre puedes usar mkdir -py touchuno después del otro:

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

Frecuentemente me encontré con este tipo de situación, así que simplemente escribí una función en mi .bashrcarchivo. Se parece a esto

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
}

Entonces, cuando quiera crear un archivo dentro de una ruta de directorios inexistentes, diré

create what/is/it  # will create dirs 'what' and 'is', with file 'it' inside 'is'
ViKiG
fuente
1
¡Mi hombre! - gracias, lo llamé touchp, comomkdir -p
ecoologic
0
dir=$(dirname "$f")
test -d $dir || mkdir -p "$dir"
Yordan Georgiev
fuente
3
El testno es necesario; mkdir -pno hace nada si el directorio ya existe. Ni siquiera devuelve un error.
derobert
1
Y, por supuesto, esto solo crea el directorio.
un CVn
0

Iba a sugerir, ya que lo mantiene en una línea, aunque establecer la variable por separado le permite cambiarlo y volver a ejecutar el comando desde el historial con bastante facilidad.

B="./make/this/path" && mkdir -p -- "$B" && touch -- "$B/file.txt"
Gilles 'SO- deja de ser malvado'
fuente
0

Es posible "fingirlo".

Primero, alguna teoría requerida:

Rob Griffiths publicó un artículo en 2007 titulado Easy Create Lots of New Folders en Macworld.com en el que discutió el uso del xargscomando para leer en una lista de archivos para crear directorios usando mkdir.

xargses capaz de hacer referencia a a placeholder( {}) con la -Ibandera, que contiene el valor de cada argumento pasado xargs. Aquí está la diferencia entre con esa bandera y sin ella:

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

xargsTambién es capaz de ejecutar comandos de shell arbitrarios con la sh -cbandera:

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

Combinando los conceptos:

Podemos combinar estos conceptos en mkdir -plugar de mkdiry el concepto en la respuesta de @ldx para producir esto:

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

Este comando básicamente asigna cada nombre de archivo en una lista de archivos separados por líneas, corta la parte del archivo, crea los directorios con mkdir -py luego touches el nombre de archivo en su directorio respectivo.

Aquí hay un desglose de lo que sucede en el comando anterior:

Digamos, por ejemplo, mi files.txtaspecto así:

deeply/nested/foo/bar.txt
deeply/nested/baz/fiz.txt
  • cat files.txt produce deeply/nested/foo/bar.js deeply/nested/baz/fiz.txt
  • deeply/nested/foo/bar.js deeply/nested/baz/fiz.txt se canaliza a xargs
  • porque usamos -I {}, xargstraducirá cada argumento a su propio comando, por lo que ahora tenemos:
    • deeply/nested/foo/bar.txt
    • deeply/nested/baz/fiz.txt
  • luego ejecutamos un comando de shell que usa el &&combinador para agrupar 3 comandos que se ejecutan secuencialmente: el primer comando almacena el archivo en una variable de entorno (que se reutiliza en el siguiente paso del archivo) usando el marcador de posición que registramos antes, así que ahora tener:
    • f=deeply/nested/foo/bar.txt
    • f=deeply/nested/baz/fiz.txt
  • ahora tenemos una variable a la que podemos pasar mkdir -p, pero necesitamos recortar el nombre del archivo. Bastante simple usando '${f%/*}':
    • mkdir -p deeply/nested/foo/
    • mkdir -p deeply/nested/baz/
  • y luego simplemente volvemos a hacer referencia a la fvariable en su totalidad cuando touch:
    • touch deeply/nested/foo/bar.txt
    • touch deeply/nested/baz/fiz.txt
barba de afeitar
fuente
2
Usted tiene toda esta explicación de lo que es esencialmente cat files.txt | xargs -I {} sh -c 'f="{}" && mkdir -p -- "${f%/*}" && touch -- "$f"', que tiene UUOC, luego se despliega en xargs que se vuelven a colocar en el shell, cuando un while readbucle tiene más sentido
Steven Penny
1
Admito que no soy el más al tanto de los comandos * nix, ni siquiera sé qué es UUOC, pero no veo cómo esta es una respuesta horrible. Se investiga, se prueba y es una solución funcional a su pregunta original. Es constructivo (a diferencia de su comentario bastante grosero). Por favor, si siente que he hecho algo irresponsable aquí que no debería haber hecho, entonces explique más: explique por qué . No me importa mucho el debate obstinado que no tiene sustancia.
razorbeard
1
Mi último comentario lo explica perfectamente. Toda su respuesta podría escribirse mejor como while read f; do mkdir -p "$(dirname "$f")"; touch "$f"; done < files.txt. El hecho de que no pueda hacer una búsqueda en Internet de 10 segundos para UUOC también es revelador
Steven Penny,