了解使用 {} 和多个 `\ls` 的复杂命令替换

了解使用 {} 和多个 `\ls` 的复杂命令替换

我试图从 shell 脚本中理解这一行。我知道这$(..)意味着运行并将其输出插入到语句中..找到的位置。$()但是这些括号之间发生了什么?这是做什么的?这与前面的内容\ls有什么关系?\这是\\两条线的分割吗?\ls和普通的一样吗ls

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

答案1

3 个命令的输出ls将传递到将paste它们合并到值中的命令:

$VOLTDB_VOLTDB"/voltdb-*.jar:$VOLTDB_LIB"/*.jar:$VOLTDB_LIB"/extension/*.jar

笔记:变量$VOLTDB_VOLTDB$VOLTDB_LIB将被扩展,并且对于这些命令中的每一个命令,可能有比只有一个文件更多的值ls。看到*那里了吗?这是一个通配符,可扩展为左侧 (voltdb-) 和右侧 (.jar) 之间的任何内容。

这些将匹配:

voltdb-1.jar
voltdb-blah.jar
voltdb-12345.jar

然后所有内容都包含在变量中APPCLASSPATH

APPCLASSPATH=$CLASSPATH:$VOLTDB_VOLTDB"/voltdb....etc.

粘贴命令

seq下面是我使用命令生成数字序列 1-10 的示例。

$ seq 10 | paste -sd ':' -
1:2:3:4:5:6:7:8:9:10

您可以看到该paste命令正在合并输出并用冒号 ( :) 分隔。

您还可以像这样模仿示例命令:

$ { echo "hi1"; echo "hi2"; echo "hi3"; } | paste -sd ':' -
hi1:hi2:hi3

笔记:to -the Past 命令告诉它从 STDIN 获取输入并打印输入的每个参数,以:.

通过不同的开关,paste还可以根据-数据后面的数量将数据分成组。

粘贴示例

这是一个带有 2-的示例。

$ seq 10 | paste - -
1       2
3       4
5       6
7       8
9       10

这是 3-的。

$ seq 10 | paste - - -
1       2       3
4       5       6
7       8       9
10

所以它告诉每行应该打印paste多少个参数。paste但不要混淆,您正在处理的示例只是从 STDIN 获取输入,用空格分隔每个参数,然后打印它,后跟:.当给出多个-' 时,您是在告诉paste您接受参数,一次 2 个,一次 3 个,等等。

一次 2 个参数,用:' 分隔:

$ seq 10 | paste -d ':' - -
1:2
3:4
5:6
7:8
9:10

$ seq 10 | paste -d ':' - - -
1:2:3
4:5:6
7:8:9
10::

顺便说一句,如果您包含-s开关,您将告诉您paste按顺序(串行)获取参数。观察当您在上面的示例之一中使用它时会发生什么。

一次 2 个:

$ seq 10 | paste -sd ':' - -
1:2:3:4:5:6:7:8:9:10

一次 3 个:

$ seq 10 | paste -sd ':' - - -
1:2:3:4:5:6:7:8:9:10

答案2

$(command)执行命令并替换其输出。

{ list; }是一个组命令,在当前shell环境中执行多个命令。它与 类似(list),但它不创建子 shell。

\command用于忽略命令的别名,这可能会大大改变命令的预期行为。

行尾\仅表示该行继续,因此 shell 会将下一行视为当前行的一部分。当从上下文(左括号或引号)中显而易见时,通常没有必要。

答案3

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

\ls与 类似ls,只不过 ifls是别名,反斜杠可防止别名扩展。这保证了ls使用该命令,而不是使用可能添加不需要的输出的别名,例如分类器后缀 ( -F)。

这些ls命令以现有文件名作为参数调用,列出其参数,每行一个。该选项-1无效,因为 的输出ls将发送到管道而不是终端。如果ls接收到的参数不是现有文件的名称,它将在其标准输出上不显示任何内容,而是显示错误。命令中的错误ls将被重定向到任何地方2> /dev/null。有两个原因ls可能会收到不是文件的参数:如果其中一个变量没有引用现有的可读目录,或者没有与通配符模式匹配的文件。无论哪种情况,模式都会以未扩展的方式传递到ls.

行末尾的反斜杠导致 shell 忽略后面的换行符。它们在这里都没有用,因为在使用它们的每个点上,shell 都需要一个可选的换行符。

大括号 { … } 对命令进行分组。复合命令{ \ls …; \ls …; \ls … ; }通过管道传输到paste并将其错误重定向到/dev/null.

paste命令将所有输入行连接在一起:。它相当于,tr '\n' :只是它没有:在末尾添加 a。

命令替换$(…)导致 的输出paste被插值到变量APPCLASSPATH值之后,CLASSPATH并用冒号分隔两部分。

这是一个简化版本。这与原始版本略有不同,因为如果没有通配符模式匹配任何内容,APPCLASSPATH则将等于CLASSPATH没有额外的尾随冒号(这可能是可取的)。

APPCLASSPATH=$CLASSPATH:$(
  \ls "$VOLTDB_VOLTDB"/voltdb-*.jar "$VOLTDB_LIB"/*.jar "$VOLTDB_LIB"/extension/*.jar |
  tr '\n' :) 2>/dev/null
APPCLASSPATH=${APPCLASSPATH%:}

相关内容