Создайте каталоги с именем из txt файла, которые содержат '/' символ

У меня есть .txt файл, который содержит текст как это

A1/B1/C1
A2/B2/C2 
A3/B3/C3

Я хочу сценарий, который читает, .txt файл для каждой строки затем создают каталог на основе первого слова (A1, A2, A3)

Я создал сценарий как это:

file="test.txt"
while IFS='' read -r line
do
    name="line"
    mkdir -p $line
done <"$file"

В то время как я выполняю его, это создает каталог A1 затем, это также создает подкаталоги B1 и C1. то же происходит для другой строки (A2* и A3*)

Что я должен сделать для создания только A1, A2, каталогов A3?

Я не хочу делать имя как A1/B1/C1 с '/' символ в нем. Я просто хочу взять слово прежде '/' символ и сделать это именем каталога. Просто "A1" "A2" "A3".

8
задан 25 May 2018 в 07:59

6 ответов

Вы можете просто cut 1наклонная черта Св. -dполе elimited каждой строки и дает список mkdir:

mkdir $(<dirlist.txt cut -d/ -f1)

Пример выполняется

$ cat dirlist.txt 
A1/A2/A3
B1/B2/B3
C1/C2/C3
$ ls
dirlist.txt
$ mkdir $(<dirlist.txt cut -d/ -f1)
$ ls
A1  B1  C1  dirlist.txt

Можно столкнуться с проблемами ARG_MAX, если список содержит огромное количество имен каталогов в этом использовании случая GNU parallel Install parallel или xargs следующим образом:

parallel mkdir :::: <(<dirlist.txt cut -d/ -f1)
xargs -a<(<dirlist.txt cut -d/ -f1) mkdir

В то время как parallel это покрыло, xargs подход не будет работать, если имена каталогов будут содержать пробелы – можно или использовать \0 как разделитель строки или просто сообщают xargs только разделять вход на символах новой строки (как предложено Martin Bonner) вместо этого:

xargs -0a<(<dirlist.txt tr \\{n,0} | cut -d/ -f1 -z) mkdir # \\{n,0} equals \\n \\0
xargs -d\\n -a<(<dirlist.txt cut -d/ -f1) mkdir

В случае, если любое из полей содержит символ новой строки, нужно было бы определить “истинные” окончания строки и заменить только те символы новой строки, например. \0. Это было бы случаем для awk, но я чувствую, что это слишком неправдоподобно здесь.

13
ответ дан 23 November 2019 в 05:21

Необходимо установить Ваш IFS='/' для read и затем присвойте каждое первое поле в отдельную переменную first и остальная часть полей в переменную rest и просто работа над значением первого поля (Или Вы можете read -ar array к единому массиву и использованию "${array[0]}" для значения первого поля.):

while IFS='/' read -r first rest;
do
    echo mkdir "$first" 
done < test.txt

Или в одной строке для тех, кому нравится он:

<test.txt xargs -d'\n' -n1 sh -c 'echo mkdir "$'{1%%/*}'"' _

Или создайте все каталоги сразу:

<test.txt xargs -d'\n' bash -c 'echo mkdir "$'{@%%/*}'"' _

ANSI-C, заключающий в кавычки $'...' используется для контакта с именами каталогов, содержащими специальные символы.

Обратите внимание что _ (может быть любой символ, или строка) в конце будет argv [0] к bash -c '...' и $@ будет содержать отдых параметров, запускающихся от 1; без этого во второй команде первый параметр к mkdir будет потерян.

В ${1%%/*} с помощью оболочки (POSIX sh/bash/Korn/zsh) расширение замены параметра, удаляет самое долгое соответствие наклонной черты, сопровождаемой чем-либо до конца передачи параметров в него, которая является строкой, которые читают xargs;

P.s:

  • Удалить echo перед mkdir создать те каталоги.
  • Замена -d'\n' с -0 если Ваш список разделяется с символами NUL вместо a \newline (предположил, существует встроенная новая строка в Вашем имени каталога).
10
ответ дан 23 November 2019 в 05:21

Содержание test.txt:

A 12"x4" dir/B b/C c
A1/B1/C1
A2/B2/C2
A3/B3/C3

Сценарий для создания A[123] папки:

file="test.txt"
while read -r line ; do
   mkdir "${line%%/*}"
done < "$file"

Вывод ls:

A 12"x4" dir
A1
A2
A3
6
ответ дан 23 November 2019 в 05:21

Для простого случая как показано во входном примере вопроса, просто используйте cut и вывод передачи к mkdir через xargs

cut -f1 -d '/' file.txt | xargs -L1 mkdir 

Для обработки случаев, где имя каталога может содержать пробелы, мы могли добавить -d '\n' к списку опций:

$ cat input.txt 
A 1/B 1/C 1
A 2/B 2/C 2
A 3/B 2/C 2
$ cut -f1 -d '/' input.txt | xargs -d '\n' mkdir 
$ ls
A 1  A 2  A 3  input.txt

Для более сложных изменений, такой как A 12"x4" dir/B b/C c как предложено @OleTange в комментариях, можно обратиться к awk создать разделенный от пустого указателя список вместо разделенного от новой строки списка.

awk -F'/' '{printf  "%s\0",$1}' input.txt |  xargs -0 mkdir

@dessert в комментариях задался вопросом ли printf может использоваться вместо cut , и с технической точки зрения это может использоваться, например, через ограничение печатной строки к ширине 3 символов только:

xargs -d '\n' printf "%.3s\n"  < input.txt | xargs -L1 mkdir 

Не самый чистый путь, но это доказывает printf может использоваться. Конечно, это становится проблематичным, если имя каталога становится дольше, чем 3 символами.

4
ответ дан 23 November 2019 в 05:21

использование Perl:

perl -ne 'mkdir for /^(\w+)/' list.txt

Или

perl -ne 'mkdir for /^([^\/]+)/' list.txt

если мы хотим принять пробелы на именах dir

2
ответ дан 23 November 2019 в 05:21

Параллель GNU может быть излишеством для задачи, но если Вы собираетесь сделать другой материал для каждой строки, затем это может быть полезно:

cat myfile.txt | parallel --colsep / mkdir {1}
parallel -a myfile.txt --colsep / mkdir {1}

Это имеет дело правильно с входом как:

A 12"x4" dir/B b/C c
0
ответ дан 23 November 2019 в 05:21

Другие вопросы по тегам:

Похожие вопросы: