如何在 Bash 中编写花式缩进的多行大括号扩展?

How to write fancy-indented multi-line brace expansion in Bash?

我正在处理这样的一行:

mkdir -p "$DEST_ROOT_PATH/"{"$DEST_DIR1","$DEST_DIR2", ..., "$DEST_DIRN"}

这一行很长。我想将其剪裁成一条 80 列的线。我试图用反斜杠转义行尾,但是 space 对齐中断了扩展:

$ echo "ha"{a,b,\
>           c}
ha{a,b, c}

这是正常行为。来自 Bash 参考手册:

3.5.1 Brace expansion

Brace expansion is a mechanism by which arbitrary strings may be generated. This mechanism is similar to filename expansion (see Filename Expansion), but the filenames generated need not exist. Patterns to be brace expanded take the form of an optional preamble, followed by either a series of comma-separated strings or a sequence expression between a pair of braces, followed by an optional postscript. The preamble is prefixed to each string contained within the braces, and the postscript is then appended to each resulting string, expanding left to right.

大括号扩展不允许在 \ 和下一行中的下一个元素之间放置的元素之间有空格。

为什么?因为它在处理时被删除:

3.1.2.1 Escape Character

A non-quoted backslash ‘\’ is the Bash escape character. It preserves the literal value of the next character that follows, with the exception of newline. If a \newline pair appears, and the backslash itself is not quoted, the \newline is treated as a line continuation (that is, it is removed from the input stream and effectively ignored).

所以当你说

something + \ + <new line> + another_thing

Bash 转换成

something + another_thing

那你能做什么?

添加一个反斜杠,然后在下一行从头开始写:

mkdir -p "$DEST_ROOT_PATH/"{"$DEST_DIR1",\
"$DEST_DIR2",\
...,\
"$DEST_DIRN"}

一些例子

当你说:

$ echo "ha"{a,b\
>    c}
ha{a,b c}

然后向上移动箭头,您会看到这是执行的命令:

$ echo "ha"{a,b   c}

所以就说:

$ echo "ha"{a,b\
> c}
haa habc

向上移动时你会看到这个:

$ echo "ha"{a,b,c}

另一个例子:

$ cat touch_files.sh
touch X{1,\
2,3}
$ bash touch_files.sh
$ ls X*
X1 X2 X3

你可以使用这个令人作呕的技巧。

echo "ha"{a,b,\
> `      `c}

它打开一个没有任何内容的子 shell,但在扩展之前得到处理,所以扩展只看到一个空的 space

所以我接受了@123的回答,这是我选择的:

mkdir -p "$DEST_ROOT_PATH/"{"$DEST_DIR1","$DEST_DIR2"}
mkdir -p "$DEST_ROOT_PATH/"{"$DEST_DIR3","$DEST_DIR4"}

这里没有很多目标目录,所以我认为它在花哨而令人作呕的 hack 和破坏缩进的令人沮丧的反斜杠之间取得了很好的平衡。

我会这样做(尽管它只解决了您创建多个目录的特定任务,并没有回答标题中所述的问题):

for d in \
      "$DEST_DIR1" \
      "$DEST_DIR2" \
       ...         \
      "$DEST_DIRn" \
      ;
do
    mkdir -p "$DEST_ROOT_PATH/$d"
done

这种方法的优点是维护列表更容易一些。

一般来说,当您注意到语法糖开始造成不便时,您应该停止坚持使用语法糖。