Bash脚本和引用


1

我正在阅读几本关于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

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


Bash是Ubuntu Gnome 16.04中的4.3.42(1)版本。它无法正确打印出文件名。当它应该在换行时断开时,它会在空格处打破它们。我试过IFS=$'\n' set - 找。-name“*” - print``和for i in "$@"; do echo $i; done。它肯定不起作用。
Diagon

啊,我明白了。你有;后的IFS=... 我不知道。这就像第二组3中的第二个案例。问题是,为什么需要这样做?我希望没有;,变量的修改应该是临时的,在下面的命令中。我不希望它是永久性的。
Diagon

回应为什么IFS=$'\n'; set - `find`;工作而不是IFS=$'\n' set - `find`;。一种可能的解释是IFS=$'\n' set - `find`;find被取代的,并与之前电流IFS记号化set执行。
guest-vm

Answers:


0

调试bash命令时我学到的两件事:一)如果它不像你认为的那样工作,请回显/打印命令,以确保它们以你认为应该的方式显示。2)手动运行命令中的命令以查看它们是否正常运行(除非这些是潜在的破坏性命令,例如: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中放置换行符。
您可以在这里阅读更多相关信息


是的,文件名中有空格,这就是问题(我在上面已经澄清过)。(1)摆脱IFS中的空间不起作用set。我确信。(2)我的理解是,在命令运行时var=value <command>应该var临时设置该值。这里命令是a for,不是吗?(3)最后命令确实有;IFS=,但它仍然即使不工作-print0应该产生空分开的文件名。
Diagon 2016年

是的,该-print0命令应该附加空字符而不是换行符; 但是bash会自动删除它们。如果要保留输出,则需要将输出保存到文件中; 但是我不确定这是你想要的,因为如果你尝试使用它们,Bash会删除空字符。正如您在此处所看到的,Bash不允许在变量中使用空字符。
Blerg 2016年

这很奇怪。它似乎也意味着IFS=''不起作用,因为我无法将IFS设置为\0
Diagon 2016年

所以在这种情况下,在使用的例子中set,唯一让我感到困惑的是IFS=$'\n' set - `find . -name "*" -print`失败,在空格中破坏文件名。
Diagon 2016年

设置<code> IFS =''</ code>与消隐它相同。由于bash忽略空字符,因此没有理由检查它们; 这意味着根本没有额外的参数分离。你可以在<code> IFS </ code>中放置你想要的任何东西,bash会将它解释为额外的参数break(字符,而不是字符串)。至于你的第二个评论,<code> IFS </ code>没有按照你想要的方式设置,直到命令完成。在<code> IFS = $'\ n'</ code>和<code> set - find . -name "*" -print</ code> 之间加一个分号,这应该可以解决您的问题。
Blerg 2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.