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

mau*_*ana 8 command-line bash directory text-processing

我有一个 .txt 文件,其中包含这样的文本

A1/B1/C1
A2/B2/C2 
A3/B3/C3
Run Code Online (Sandbox Code Playgroud)

我想要一个脚本来读取每一行的 .txt 文件,然后根据第一个单词(A1、A2、A3)创建一个目录

我已经创建了这样的脚本:

file="test.txt"
while IFS='' read -r line
do
    name="line"
    mkdir -p $line
done <"$file"
Run Code Online (Sandbox Code Playgroud)

当我运行它时,它会创建目录 A1,然后还会创建子目录 B1 和 C1。另一行(A2* 和 A3*)也会发生同样的情况

我应该怎么做才能只创建 A1、A2、A3 目录?

我不想让名字像 A1/B1/C1 那样带有 '/' 字符。我只想在 '/' 字符之前取这个词并将其设为目录名。只是“A1”“A2”“A3”。

des*_*ert 14

您可以只cut使用每行的1st 斜杠d分隔字段并将列表提供给mkdir

mkdir $(<dirlist.txt cut -d/ -f1)
Run Code Online (Sandbox Code Playgroud)

示例运行

$ 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
Run Code Online (Sandbox Code Playgroud)

如果您的列表包含大量目录名称,您可能会遇到ARG_MAX问题,在这种情况下使用 GNUparallel 平行安装xargs如下:

parallel mkdir :::: <(<dirlist.txt cut -d/ -f1)
xargs -a<(<dirlist.txt cut -d/ -f1) mkdir
Run Code Online (Sandbox Code Playgroud)

虽然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
Run Code Online (Sandbox Code Playgroud)

如果任何字段包含换行符,则需要识别“真正的”行尾,并仅将这些换行符替换为例如\0. 这将是 的情况awk,但我觉得这里太牵强了。


αғs*_*нιη 12

您需要设置IFS='/'forread然后将每个第一个字段分配给单独的变量first,将其余字段分配给变量,rest然后只处理第一个字段的值(或者您可以read -ar array使用单个数组并"${array[0]}"用于第一个字段的值。):

while IFS='/' read -r first rest;
do
    echo mkdir -- "$first" 
done < test.txt
Run Code Online (Sandbox Code Playgroud)

###Or 对于喜欢它的人来说,单行:

<test.txt xargs -d'\n' -n1 sh -c 'echo mkdir -- "$'{1%%/*}'"' _
Run Code Online (Sandbox Code Playgroud)

###或一次性创建所有目录:

<test.txt xargs -d'\n' bash -c 'echo mkdir -- "$'{@%%/*}'"' _
Run Code Online (Sandbox Code Playgroud)

ANSI-C报价$'...'是用来处理包含特殊字符的目录名称。

请注意,_末尾的(可以是任何字符或字符串)将是 argv[0] 到 thebash -c '...'并且该$@will 包含从 1 开始的其余参数;如果没有在第二个命令中,第一个参数mkdir将丢失。

${1%%/*}使用shell (POSIX sh/bash/Korn/zsh) 参数替换扩展时,删除斜杠后跟任何内容的最长可能匹配,直到传递给它的参数结束,这是由xargs读取的一行;

附:

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


xio*_*ota 6

内容test.txt

A 12"x4" dir/B b/C c
A1/B1/C1
A2/B2/C2
A3/B3/C3
Run Code Online (Sandbox Code Playgroud)

创建A[123]文件夹的脚本:

file="test.txt"
while read -r line ; do
   mkdir "${line%%/*}"
done < "$file"
Run Code Online (Sandbox Code Playgroud)

的输出ls

A 12"x4" dir
A1
A2
A3
Run Code Online (Sandbox Code Playgroud)


Ser*_*nyy 5

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

cut -f1 -d '/' file.txt | xargs -L1 mkdir 
Run Code Online (Sandbox Code Playgroud)

对于处理目录名称可能包含空格的情况,我们可以添加-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
Run Code Online (Sandbox Code Playgroud)

对于更复杂的变体,例如A 12"x4" dir/B b/C c@OleTange 在评论中所建议的,可以转向awk创建空分隔列表而不是换行分隔列表。

awk -F'/' '{printf  "%s\0",$1}' input.txt |  xargs -0 mkdir
Run Code Online (Sandbox Code Playgroud)

评论中的@dessert 想知道是否printf可以使用 代替cut,从技术上讲可以使用它,例如通过将打印的字符串限制为仅 3 个字符的宽度:

xargs -d '\n' printf "%.3s\n"  < input.txt | xargs -L1 mkdir 
Run Code Online (Sandbox Code Playgroud)

不是最干净的方式,但它证明printf 可以使用。当然,如果目录名称变得超过 3 个字符,这就会出现问题。