Zsh:读取从文件到数组的行

Rob*_*bie 5 arrays file-io zsh

我试图在一个文件中读取一个行数组然后遍历它zsh,并且我大部分时间都得到了代码,除非输入文件包含某些字符(如括号).这是它的片段:

#!/bin/zsh
LIST=$(cat /path/to/some/file.txt)
SIZE=${${(f)LIST}[(I)${${(f)LIST}[-1]}]}
POS=${${(f)LIST}[(I)${${(f)LIST}[-1]}]}
while [[ $POS -le $SIZE ]] ; do
    ITEM=${${(f)LIST}[$POS]}
    # Do stuff
    ((POS=POS+1))
done
Run Code Online (Sandbox Code Playgroud)

这样做会更简单吗?我还需要计算文件中的行数.

ZyX*_*ZyX 11

#!/bin/zsh
zmodload zsh/mapfile
FNAME=/path/to/some/file.txt
FLINES=( "${(f)mapfile[$FNAME]}" )
LIST="${mapfile[$FNAME]}" # Not required unless stuff uses it
integer POS=1             # Not required unless stuff uses it
integer SIZE=$#FLINES     # Number of lines, not required unless stuff uses it
for ITEM in $FLINES
    # Do stuff
    (( POS++ ))
endfor
Run Code Online (Sandbox Code Playgroud)

你的代码中有一些奇怪的东西:

  1. 你为什么LIST每次分裂而不是把它变成数组变量?这只是浪费CPU时间.
  2. 你为什么不用for ITEM in ${(f)LIST}
  3. 有可能直接询问zsh有关数组长度的信息:$#ARRAY.无需确定最后一个元素的索引.
  4. POS获得与SIZE代码中相同的值.因此它只会迭代一次.
  5. 括号是可能的问题,因为3:(I)匹配模式.阅读文档.


Pab*_*oni 6

我知道问题得到解答已经有很多时间,但我认为值得发布一个更简单的答案(不需要zsh/mapfile外部模块):

#!/bin/zsh
for line in "${(@f)"$(</path/to/some/file.txt)"}"
{
  // do something with each $line
}
Run Code Online (Sandbox Code Playgroud)

  • mapfile 不会产生子进程,因此速度更快;zsh/mapfile 也随 zsh 一起提供。顺便说一句,我发现对某些人来说可能是个问题:这个问题的解决方案都没有保留空行。我的两次空行丢失:在`(f)`(需要`(@f)`,并且还需要删除尾随的空项目)和`for ITEM in $LINES`(需要`for ITEM in "${LINES[ @]}"`)。你的三次:相同加上`( $arr )` 也会失去它们,需要双引号。 (2认同)
  • @HappyFace shell 不会将其解析为嵌套字符串,而是将其解析为双引号字符串,然后是 $() 扩展,然后是另一个双引号字符串。按顺序评估它们并连接结果。 (2认同)

小智 6

出于示例目的,假设其中file.txt包含以下文本:

one

two

three
Run Code Online (Sandbox Code Playgroud)

解决方案取决于您是否要删除中的空行file.txt




最后,结果数组的差异是大括号扩展期间是否提供参数扩展标志的结果。 (@)

  • @cassepipe 总结一下:`(@f)` 是“参数扩展标志”。`f` 在换行符处将结果分割成单独的“单词”(即“\n”,也可能是“\r”,但我不确定)。即使在引用时,“@”也确保扩展结果被分成单独的单词。引号本身确保空字符串“''”不会被删除,因此您通常需要“@”和引号。`$(&lt;file)` 语法是命令替换语法的扩展,它只是读取文件的内容,如 `$(cat file)` 但不生成外部进程。 (2认同)
  • 最后,“( ... )”定义了一个数组,将每个单词放入一个单独的数组元素中。因此,整个咒语首先从文件中读取,将每一行拆分为一个单独的单词,然后将每个单词放入一个单独的数组元素中,包括完全空的行。请注意,“typeset -a”在这里是多余的,您可以只写“lines=( ... )”,它会以相同的方式工作。 (2认同)