it-swarm-eu.dev

rekurzivní mkdir

Existuje nějaký linuxový příkaz, který přehlížím a který umožňuje dělat něco podle: (pseudo)

$ mkdir -R foo/bar/Zoo/andsoforth

Nebo neexistuje jiná možnost, než vytvořit adresáře jeden po druhém?

344
Dr.Dredel
$ mkdir -p foo/bar/Zoo/andsoforth
576
EEAA

Pomocí mkdir -p je jednoduchý způsob pro většinu moderních operačních systémů:

mkdir -p foo/bar/Zoo/andsoforth

Nicméně, mkdir -p se v mnoha příručkách nedoporučuje. Přečtěte si dokumentaci o GNU make a autoconf o problémech s používáním mkdir -p:

Instalační a konfigurační systémy napříč platformami mají své vlastní bezpečné alternativy pro mkdir -p.

CMake použít v příkazovém řádku Shell:

 cmake -E make_directory foo/bar/Zoo/andsoforth

Autoconf pro použití ve skriptu s předběžným zpracováním:

AS_MKDIR_P(foo/bar/Zoo/andsoforth)

nebo:

AC_PROG_MKDIR_P(foo/bar/Zoo/andsoforth)

Tato řešení však vyžadují cmake nebo autoconf (M4) nainstalované nástroje (a možné předzpracování)

Můžete také použít install-sh skript s -d možnost:

install-sh -d foo/bar/Zoo/andsoforth

Tento skript je používán v projektech autoconf a automake. Myslím, že to musí být nejbezpečnější řešení.

V té době jsem hledal řešení napříč platformami pro standardní /bin/sh bez závislostí, ale jednu jsme nenašli. Proto jsem napsal další skript, který nemusí být ideální, ale myslím si, že vyhovuje většině požadavků napříč platformami :

#! /bin/sh

cdirname() # cross platform alternative for 'dirname'
{
  # $1 - path
  test $# -eq 1 || { echo "Procedure 'cdirname' must have only one parameter. Scripting error."; exit 1; }
  echo "$1" | sed -n -e '1p' | sed  -e 's#//*#/#g' -e 's#\(.\)/$#\1#' -e 's#^[^/]*$#.#' -e 's#\(.\)/[^/]*$#\1#' -
}

mkd() # cross platform alternative for 'mkdir -p'
{
  # $1 - directory to create
  test $# -eq 1 || { echo "Function 'mkd' can create only one directory (with it's parent directories)."; exit 1; }
  test -d "$1"  && return 0
  test -d "$(cdirname "$1")" || { mkd "$(cdirname "$1")" || return 1; }
  test -d "$1" || { mkdir "$1" || return 1; }
  return 0
}

Tento skript lze použít pro staré systémy, kde možnost -p pro mkdir chybí.

Do kódu byla přidána verze platformy sed založená na platformě dirname. Funguje podobným způsobem jako dirname (opraveno s cestou /, cesty pouze se základním názvem, cesty s koncem /, cesty s koncem a bez konců \ns). Tato funkce nemůže fungovat správně, pokud cesta obsahuje nové řádky nebo neplatné znaky pro aktuální národní prostředí. Nahrazuje také jakoukoli kombinaci / (//, ///) s jedním /

Změněný řádek mkdir "$1" || return 1 to test -d "$1" || { mkdir "$1" || return 1; } protože mkdir končí chybou, pokud existuje cesta a tato kontrola je nutná pro cesty obsahující konstrukce jako aaa\. (Pokud aaa neexistuje, předchozí verze vytvoří aaa a poté se ji pokusí znovu vytvořit).

Tato verze mkd negeneruje chybu, pokud již cesta existuje (ale stále má možnost generovat takovou chybu při paralelním provádění) a na příkazovém řádku nemůže získat několik adresářů.

Možnost -p v příkazu mkdir vytvoří p arent adresáře podle potřeby (bez chyby, pokud existuje):

mkdir -p foo/bar/Zoo/andsoforth

Jiným způsobem je například použití && (chyba, pokud zadaná složka existuje):

mkdir foo && mkdir foo/bar && mkdir foo/bar/Zoo && mkdir foo/bar/Zoo/andsoforth

Operátor řetězení && se používá pro zřetězení příkazů dohromady, takže další příkaz se spustí pouze tehdy, pokud předchozí příkaz skončil bez chyb.

První způsob je samozřejmě lepší.

0
simhumileco