为每个通配符匹配创建命令替换

时间:2020-10-05 01:21:03

标签: linux bash

假设我有一个文件夹foo,其中包含文件ab(也许还有更多)。

我想将paste中的每个文件(这里是文件fooa)的命令替换传递给b

差不多了:

paste <(cut -f1 /foo/*)

但是,它扩展为:

    paste <(cut -f1 /foo/a /foo/b)

我实际上想要的是foo中每个文件的单独替换:

    paste <(cut -f1 /foo/a) <(cut -f1 /foo/b)

解决方案不必一定涉及命令替换,这只是我制定的方式。

2 个答案:

答案 0 :(得分:4)

您的问题是<(command group)隐式创建了一个FIFO,但是此FIFO仅在当前命令范围内存在。这意味着,您无法将此FIFO保存到变量中,以后再使用它的流。调用命令完成执行后已释放。

让我们演示一下:

echo <(:) <(:); echo <(:)

输出:

/dev/fd/63 /dev/fd/62
/dev/fd/63

第二个echo将重置子外壳程序命令组已分配的文件描述符编号。

相反,一个选项是显式创建命名的FIFO,因为它们一直存在到显式删除为止,因此可以保存其引用文件名以备后用:

#!/usr/bin/env bash

tmpdir=$(mktemp -d)

trap 'rm -fr -- "$tmpdir"' EXIT

n=0

fifo_arr=()

for f in 'foo/'*; do
  fifo="$tmpdir/$((n++))"
  mkfifo "$fifo"
  fifo_arr+=("$fifo")
  cut -f1 "$f" >"$fifo" &
done

paste "${fifo_arr[@]}"

答案 1 :(得分:2)

好的,这就是我的想法。

ls *.txt | tr -s ' ' '\n' | sed -E 's/^(.*)$/<(cut -f1 \1)/' | tr -s '\n' ' ' | awk '{ print; }' > cmd.output; sed -i -E 's/^([^\s]+)/paste \1/' cmd.output; bash cmd.output

当前目录中有两个文件,a.txtb.txt

第一个仅包含以下内容。

a
b
c

第二个文件是相似的。

1
2
3

我首先获取所有感兴趣的文件。在此示例中,所有*.txt文件。

$ ls *.txt
a.txt b.txt

然后我通过将每个空格转录为换行符来将它们分成自己的一行(我想col也适用于此行)。

$ ls *.txt | tr -s ' ' '\n'
a.txt
b.txt

接下来,我使用cut正则表达式替换为列出的每个文件创建sed命令。

$ ls *.txt | tr -s ' ' '\n' | sed -E 's/^(.*)$/<(cut -f1 \1)'
<(cut -f1 a.txt)
<(cut -f1 b.txt)

我现在反转换行符空间的转录,以将其重新格式化为单行。

$ ls *.txt | tr -s ' ' '\n' | sed -E 's/^(.*)$/<(cut -f1 \1)'
<(cut -f1 a.txt) <(cut -f1 b.txt)

然后我将其通过管道传输到文件cmd.sh(我正在使用tee来查看实验时摆弄的结果。)

$ ls *.txt | tr -s ' ' '\n' | sed -E 's/^(.*)$/<(cut -f1 \1)' > cmd.sh

已经建立了命令参数,然后我使用了另一个sed正则表达式来编辑命令文件,将<args>替换为paste <args>

$ sed -i -E 's/^([^\s]+)/paste \1/' cmd.sh

之前:

$ cat cmd.sh
<(cut -f1 a.txt) <(cut -f1 b.txt)

之后:

$ cat cmd.sh
paste <(cut -f1 a.txt) <(cut -f1 b.txt)

最后,我调用bash,将文件名作为参数传递。

$ bash cmd.sh
a   1
b   2
c   3

我很想知道是否有人找到更好的解决方案。这似乎...很黑。