У меня есть .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".
Вы можете просто 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
или 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
, но я чувствую, что это слишком неправдоподобно здесь.
Необходимо установить Ваш 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 \n
ewline (предположил, существует встроенная новая строка в Вашем имени каталога).Содержание 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
Для простого случая как показано во входном примере вопроса, просто используйте 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 символами.
использование Perl:
perl -ne 'mkdir for /^(\w+)/' list.txt
Или
perl -ne 'mkdir for /^([^\/]+)/' list.txt
если мы хотим принять пробелы на именах dir
Параллель GNU может быть излишеством для задачи, но если Вы собираетесь сделать другой материал для каждой строки, затем это может быть полезно:
cat myfile.txt | parallel --colsep / mkdir {1}
parallel -a myfile.txt --colsep / mkdir {1}
Это имеет дело правильно с входом как:
A 12"x4" dir/B b/C c