Bash: 停止函数参数的变量扩展
Bash: stop variable expansion for function argument
我正在尝试编写一个具有日志记录功能的 bash 脚本:
log() {
echo 2>&1
}
我检查了以下命令的输出:
ARCHIVE_PREFIX= // value = myFile
ARCHIVE_FILE_PATTERN="${ARCHIVE_PREFIX}-*.zip" // looking for zip archive starting with my file
log "Searching current directory for pattern - log: $ARCHIVE_FILE_PATTERN"
echo "Searching current directory for pattern - echo: $ARCHIVE_FILE_PATTERN"
我希望最后两行打印相同的内容,但输出结果是:
Searching current directory for pattern - log: myFile-08022022.zip // an archive from current working dir
Searching current directory for pattern - log: myFile-*.zip
谁能解释一下为什么会这样,我该如何更改逻辑以便函数使用实际变量值?
您尝试打印的变量是所有结果的数组。
你必须遍历数组来打印每个元素,就像这样
for FILE in $ARCHIVE_FILE_PATTERN
do
log "Searching current directory for pattern - log: $FILE"
echo "Searching current directory for pattern - echo: $FILE"
done
我不确定 bash 循环的语法,但你知道如果这不起作用,你可以重写它。
正如 Biffen 所说,这是因为 log
中的 </code> 引用未被引用。这是一个重现问题的小例子:</p>
<pre><code>$ ls -l
total 0
-rw-r--r-- 1 igstan staff 0 Mar 9 12:55 bar.md
-rw-r--r-- 1 igstan staff 0 Mar 9 12:55 foo.md
$ PATTERN=*.md
$ echo "$PATTERN"
*.md
$ echo $PATTERN
bar.md foo.md
在你的情况下,没有引号,echo
将:
- 将
</code>扩展为<code>myFile-*.zip
,这是一个glob pattern
- 将 glob 模式扩展为 一个列表 与模式匹配的文件
- 回显列表
所以解决方法是引用它:
log() {
echo "" 2>&1
}
此外,我认为您不想将 stderr (2
) 重定向到 stdout (1
),但可能相反,将 stdout 重定向到 stderr,这样就不会记录日志“正常”程序输出的一部分:
log() {
echo "" 1>&2
}
然而,如果我们用 previously-declared PATTERN
变量测试它,我们会看到这种情况发生:
$ log "$PATTERN"
*.md
$ log $PATTERN # glob pattern is expanded before being passed to `log`
bar.md
第二种情况,只有一个文件名被打印出来。这是因为 glob 扩展为文件名的 列表 (松散地说),所以如果你真的想要灵活地打印整个结果,你必须从 </code> 到 <code>$@
(函数的所有参数)在 log
函数内:
log() {
echo "$@" 1>&2
}
我们现在有这些结果:
$ log "$PATTERN"
*.md
$ log $PATTERN # glob pattern is expanded before being passed to `log`
bar.md foo.md
我正在尝试编写一个具有日志记录功能的 bash 脚本:
log() {
echo 2>&1
}
我检查了以下命令的输出:
ARCHIVE_PREFIX= // value = myFile
ARCHIVE_FILE_PATTERN="${ARCHIVE_PREFIX}-*.zip" // looking for zip archive starting with my file
log "Searching current directory for pattern - log: $ARCHIVE_FILE_PATTERN"
echo "Searching current directory for pattern - echo: $ARCHIVE_FILE_PATTERN"
我希望最后两行打印相同的内容,但输出结果是:
Searching current directory for pattern - log: myFile-08022022.zip // an archive from current working dir
Searching current directory for pattern - log: myFile-*.zip
谁能解释一下为什么会这样,我该如何更改逻辑以便函数使用实际变量值?
您尝试打印的变量是所有结果的数组。 你必须遍历数组来打印每个元素,就像这样
for FILE in $ARCHIVE_FILE_PATTERN
do
log "Searching current directory for pattern - log: $FILE"
echo "Searching current directory for pattern - echo: $FILE"
done
我不确定 bash 循环的语法,但你知道如果这不起作用,你可以重写它。
正如 Biffen 所说,这是因为 log
中的 </code> 引用未被引用。这是一个重现问题的小例子:</p>
<pre><code>$ ls -l
total 0
-rw-r--r-- 1 igstan staff 0 Mar 9 12:55 bar.md
-rw-r--r-- 1 igstan staff 0 Mar 9 12:55 foo.md
$ PATTERN=*.md
$ echo "$PATTERN"
*.md
$ echo $PATTERN
bar.md foo.md
在你的情况下,没有引号,echo
将:
- 将
</code>扩展为<code>myFile-*.zip
,这是一个glob pattern - 将 glob 模式扩展为 一个列表 与模式匹配的文件
- 回显列表
所以解决方法是引用它:
log() {
echo "" 2>&1
}
此外,我认为您不想将 stderr (2
) 重定向到 stdout (1
),但可能相反,将 stdout 重定向到 stderr,这样就不会记录日志“正常”程序输出的一部分:
log() {
echo "" 1>&2
}
然而,如果我们用 previously-declared PATTERN
变量测试它,我们会看到这种情况发生:
$ log "$PATTERN"
*.md
$ log $PATTERN # glob pattern is expanded before being passed to `log`
bar.md
第二种情况,只有一个文件名被打印出来。这是因为 glob 扩展为文件名的 列表 (松散地说),所以如果你真的想要灵活地打印整个结果,你必须从 </code> 到 <code>$@
(函数的所有参数)在 log
函数内:
log() {
echo "$@" 1>&2
}
我们现在有这些结果:
$ log "$PATTERN"
*.md
$ log $PATTERN # glob pattern is expanded before being passed to `log`
bar.md foo.md