【问题标题】:Bash script to mkdir on each line of a file that has been split by a delimiter?在已被分隔符分割的文件的每一行上将 Bash 脚本写入 mkdir?
【发布时间】:2018-02-02 01:42:03
【问题描述】:

试图弄清楚如何逐行遍历 .txt 文件 (filemappings.txt),然后使用 tab(\t) 作为分隔符分割每一行,以便我们可以创建指定的目录选项卡的右侧 (mkdir -p)。

读取filemappings.txt,然后用tab分割每一行

server/ /client/app/
server/a/   /client/app/a/
server/b/   /client/app/b/

会变成

mkdir -p /client/app/
mkdir -p /client/app/a/
mkdir -p /client/app/b/

xargs 会是一个不错的选择吗?为什么或为什么不?

【问题讨论】:

  • 顺便说一句——文件名允许包含制表符(或换行符!),因此这不是用于完全任意名称的好文件格式;通常,不受信任的名称列表应始终以 NUL 分隔。

标签: linux bash xargs


【解决方案1】:
cut -f 2 filemappings.txt | tr '\n' '\0' | xargs -0 mkdir -p 

xargs -0 非常适合向量运算。

【讨论】:

  • 您的意思可能是-f2?我认为你可以只使用xargs -d'\n' ...。我认为将\n 转换为\0 然后使用xargs -0 没有任何意义(也许有区别?)。
  • @PesaThe:是的 -f1 是一个错误。出于习惯,我把 '\n' 变成了 '\0',而不是知道这样做的理由。
  • 因为it wasn't obvious to the OP 可能会指出xargs 将尽可能少地运行mkdir -p,并将多个目录作为其参数。这很好用,并且对于接受任意文件或目录名称列表作为参数的命令来说是一个很好的优化;但在其他一些场景中显然不太理想。
  • 抱歉,链接错误;另一个问题是stackoverflow.com/q/48308990/874188
【解决方案2】:

你已经有一个答案告诉你如何使用xargs。根据我的经验,xargs 在您想在易于检索的 参数 列表上运行简单命令时很有用。在您的示例中,xargs 会做得很好。但是,如果您想做一些比运行简单命令更复杂的事情,您可能需要使用while 循环:

while IFS=$'\t' read -r a b
do
  mkdir -p "$b"
done <filemappings.txt

在这种特殊情况下,read a b 将读取由定义的IFS 分隔的两个参数,并将每个参数放入不同的变量中。如果你是单线爱好者,你也可以这样做:

while IFS=$'\t' read -r a b; do mkdir -p "$b"; done <filemappings.txt

通过这种方式,您可以读取多个参数以应用于任何一系列命令; xargs 不太适合做的事情。

使用read -r 将逐行读取,而不管其中是否有任何反斜杠,以防您需要读取带有反斜杠的行。

另请注意,某些操作系统可能允许选项卡作为文件或目录名称的一部分。这会破坏制表符作为参数分隔符的使用。

【讨论】:

  • 所以,有几件事值得一提。 1) 引用:"$b" 2) IFS=\t 不起作用。你必须使用IFS=$'\t' 3) 你正在为脚本的其余部分更改IFS(这可能会搞砸事情)。只为 read 声明它 cmd: IFS=$'\t' read ... 4) read 没有 -r 将处理反斜杠。
  • @PesaThe,我已经测试了我的答案,IFS=\t 对我有用。我也尝试过IFS=$'\t',但它对我不起作用。你是对的,为单个语句定义变量是要走的路,但我已经用while 语句尝试过它,它对我不起作用。关于$b 周围的报价,您是完全正确的。已修复,谢谢。
  • @PesaThe,在正确的地方测试了IFS=$'\t'... :-) 现在它可以工作了。我也解决了这个问题;正如您所说,为脚本的其余部分更改 IFS 并不理想。再次感谢。
  • IFS=\t 不应该工作,因为它会拆分文字 t 字符:) 请参阅此 snippet。最后说明:考虑添加 -r 选项,以便允许包含反斜杠的目录。
  • @PesaThe,考虑接受,谢谢!我已更改说明以包含 -r 选项。
【解决方案3】:

正如其他人指出的那样,\t 字符也可能是文件或目录名称的一部分,以下命令可能会失败。假设问题代表输入文件的真实形式,可以使用:

  $ grep -o -P '(?<=\t).*' filemappings.txt | xargs -d'\n' mkdir -p

它使用-P perl 风格的正则表达式来获取\t(TAB) 字符之后的单词,然后使用-d'\n' 将所有相关行作为单个输入提供给mkdir -p

【讨论】:

  • 你是对的。 -d'\n' 确实会随着大量输入行进行缩放。已编辑。
【解决方案4】:
sed -n '/\t/{s:^.*\t\t*:mkdir -p ":;s:$:":;p}' filemappings.txt | bash

  1. sed -n:仅适用于包含 tab(分隔符)的行
  2. s:^.*\t\t*:mkdir -p :: 将所有内容从 line beggning 更改为 tabmkdir -p
  3. | bash:告诉bash创建文件夹

【讨论】:

  • xargs 在不创建太长的命令行的情况下尽可能少地运行其命令,因此在 Joshua 的回答中,它只会运行一次 mkdir,而您的解决方案运行每行一次。
  • 加上路径中有"是不行的,可以用来执行任意代码!
【解决方案5】:

使用 GNU Parallel,它看起来像这样:

parallel --colsep '\t' mkdir -p {2} < filemapping.txt

【讨论】:

    猜你喜欢
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    • 1970-01-01
    相关资源
    最近更新 更多