Bash 脚本和引用

Bash 脚本和引用

我正在阅读几本关于 bash 脚本的书,但一直无法理解正确的引号和用法IFS。也许有人可以帮我举一个带引号的文件名的小例子。从命令行执行此操作,即使文件名中包含空格,也可以正确打印出文件名:

set - *
for i in "$@"; do echo $i; done

这不起作用,因为它在空格处中断:

set - `find . -name "*"`
for i in "$@"; do echo $i; done

也不会:

IFS=$'\0' set - `find . -name "*" -print0`
for i in "$@"; do echo $i; done

IFS=$'\n'使用和的组合也不会-print。为什么这些都失败了?

以下操作也会失败,但在这种情况下会出错(“bash:意外标记“do”附近有语法错误”)。为什么?

IFS=$'\n' for i in `find . -name "*" -type f`; do echo $i; done 

但这有效(注意“;”):

IFS=$'\n'; for i in `find . -name "*" -type f`; do echo $i; done 

但此操作会失败,因为文件名根本没有拆分(循环for仅一次):

IFS=''; for i in `find . -name "*" -type f -print0`; do echo -e "$i\n"; done

那么,为什么第一个和第三个会失败呢?

最后,我是否正确地认为当设置时IFS''与相同$'\0'?(我在前面的例子中尝试了两者。)如果是这样,为什么我显然需要$'\n'而不是仅仅\n

*Ubuntu Gnome 16.04 中的 Bash 版本为 4.3.42(1)。

答案1

在调试 bash 命令时我学到了两件事:第一)如果它没有像您认为的那样工作,请 echo/printf 输出命令以确保它们按您认为的方式显示。第二)手动运行命令中的命令以查看它们是否正常运行(除非这些命令具有潜在的破坏性,例如:rm、dd、chmod 777 等)。

您究竟想如何完成或完成什么?我的命令似乎可以逐字逐句地正常工作,因此您需要解释您希望它做什么。您的文件名中是否有空格导致命令出现问题?只要您从 IFS 变量中删除空格,它可能会按您想要的方式工作:IFS=$'\n\t'。该-print0选项基本上会删除所有行分隔符,因此除非文件名称中有空格,否则您希望从这些命令中获得的所有内容都没有分隔符。对于您的第二组问题:

IFS=$'\n' for i in `find . -name "*" -type f`; do echo $i; done 

此命令无法正常运行,因为 bash 是这样读取它的:

IFS=$'\n' for i in `find . -name "*" -type f`
do echo $i
done

第一行将 IFS 设置为:$'\n' for i in。之后,下一行读为:do echo $i,这不起作用,因为该do命令需要某种循环作为前一个命令。下一个有效,因为分号告诉 bash 已到达命令末尾,因此:

IFS=$'\n'
for i in `find . -name "*" -type f`
do echo $i
done 

最后,我是否正确地认为,当设置 IFS 时,'' 与 $'\0' 相同?(我在前面的例子中尝试了两者。)如果是这样,为什么我显然需要 $'\n' 而不是 \n?

第一部分是的,'''\0'都被视为 NULL,因此它们基本相同。这是因为 bash 将其解释$''为 ANSI C 字符串。并且您需要在 \n 周围加上引号,以便 bash 将其解释为 C 字符串,这样换行符就会放在 IFS 中。
您可以阅读更多有关这些的内容这里

相关内容