从txt文件中使用包含“ /”字符的名称创建目录


8

我有一个.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”。

Answers:


13

您可以仅cut在每行的1斜线d分隔字段中输入,并将列表提供给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

如果任何字段包含换行符,则需要标识“ true”行尾,并仅将这些换行符替换为例如\0。可能是这种情况awk,但我觉得这里牵强了。


为什么xargs -a<(....)而不是<dirlist.txt cut -d/ -f1 | xargs
马丁·邦纳

1
@MartinBonner感谢您的澄清,这确实比我的tr方法更简单-只是意识到parallel默认情况下已覆盖它。
甜点

@MartinBonner 为什么xargs -a<(....)而不是管道 –因为我喜欢这种方式,就这么简单。:)
甜点

@AndreaCorbellini哦,现在我明白了。<(...)空格也有帮助,因此绝对是更好的选择–我认为任何人都不会使用此文件描述符。
甜点


11

您需要设置IFS='/'for 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 '...'并且$@will包含从1开始的其余参数;在第二个命令中没有该命令的第一个参数mkdir将丢失。

${1%%/*}使用shell(POSIX sh / bash / Korn / zsh)参数替换扩展时,删除斜杠的最长匹配项,然后删除所有内容,直到传递给它的参数末尾为止,这是xargs读取的行;

附:

  • 删除echomkdir以创建这些目录。
  • 更换-d'\n'-0,如果你的列表与NULL字符,而不是分开的\newline(应该有你的目录名/嵌入换行符)。

6

内容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

您如何处理像这样的输入A 12"x4" dir/B b/C c
Ole Tange

Ole Tange-该评论似乎完全超出了该问题的范围。
DocSalvager

4

对于简单的情况,如问题的输入示例所示,只需使用cut 并将输出传递给mkdirviaxargs

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个字符,这将成为问题。


您如何处理像这样的输入A 12"x4" dir/B b/C c
Ole Tange

@OleTange参见编辑。
Sergiy Kolodyazhnyy

2

使用Perl:

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

要么

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

如果我们要接受目录名上的空格


1
perl -ne 'mkdir for /^([^\/]+)/' list.txt覆盖目录名称中的空格。我最终需要学习Perl –谢谢!
甜点

0

GNU Parallel可能对这项任务有些过分,但是如果您要为每一行做其他事情,那么它可能会很有用:

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

它可以正确处理以下输入:

A 12"x4" dir/B b/C c
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.