用bash逐字符阅读


8

我一直在尝试使用bash逐字符读取文件。

经过多次试验和错误,我发现这可行:

exec 4<file.txt 
declare -i n
while read -r ch <&4; 
     n=0
     while [ ! $n -eq ${#ch} ]
           do  echo -n "${ch:$n:1}"
               (( n++ ))
          done
     echo "" 
     done

即,我可以逐行读取它,然后逐字符逐个循环。

在执行此操作之前,我已经尝试过: exec 4<file.txt && while read -r -n1 ch <&4; do; echo -n "$ch"; done 但是它将跳过file中的所有空格

你能解释为什么吗?有没有办法使第二种策略(即用bash的read逐字符读取char)起作用?


4
设置IFS为空时不让空格在单词拆分中存活。
manatwork,2012年

使用IFS =进行了尝试,但是我想那只能是IFS =。谢谢!
PSkocik

Answers:


12

您需要从$IFS参数中删除空格字符,read以停止跳过前导和尾随的-n1字符(使用时,如果有空格字符,则将同时出现前导和尾随的字符,因此跳过):

while IFS= read -rn1 a; do printf %s "$a"; done

但是即使那样,bash read也会跳过换行符,您可以使用以下方法:

while IFS= read -rn1 a; do printf %s "${a:-$'\n'}"; done

尽管您可以改用IFS= read -d '' -rn1甚至更好IFS= read -N1(在4.1中添加,从ksh93(中添加o)复制),这是读取一个字符的命令。

请注意,bash read无法应付NUL字符。而ksh93具有与bash相同的问题。

使用zsh:

while read -ku0 a; do print -rn -- "$a"; done

(zsh可以处理NUL字符)。

请注意,那些read -k/n/N读取的是字符,而不是字节。因此,对于多字节字符,它们可能必须读取多个字节,直到读取完整字符为止。如果输入包含无效字符,则您可能会得到一个变量,该变量包含一个不构成有效字符的字节序列,并且外壳可能最终被算作几个字符。例如在UTF-8语言环境中:

$ printf '\375\200\200\200\200ABC' | bash -c '
    IFS= read  -rN1 a; echo "${#a}"'
6

\375将引入一个6字节的UTF-8字符。但是,上面的第六个(A)对于UTF-8字符无效。你还是最终了\375\200\200\200\200A$a,其bash计为6 个字符,虽然前5成的人是不是真的字符,只有5个字节没有形成任何字符的一部分。


谢谢。简单而美丽。实际上,我为此尝试了一些操作(修改IFS变量),但是它对我没有用,所以我最终选择了我的混合物(不必要地使用文件描述符等)。
PSkocik

1
有趣的是,看起来好像改用read -rN1来解决换行问题,从而消除了打印时默认提供换行的需要$a
krb686 '16

只是FTR,我正在读取4118行20 MB文件。使用read -n1(一个字符一个字符)需要4分钟 51秒,并将笔记本电脑加热到90度。使用read -r(逐行)耗时1.3秒,笔记本电脑保持54度,双风扇静音。
WinEunuuchs2Unix

2

这是使用cutfor循环&的简单示例wc

bytes=$(wc -c < /etc/passwd)
file=$(</etc/passwd)

for ((i=0; i<bytes; i++)); do
    echo $file | cut -c $i
done

不是吗?


如果是KISS,那么什么是纯粹的bash解决方案:file="$(</etc/passwd)"; bytes="${#file}"; for ((i=0;i<bytes;i++)); do echo "${file:i:1}"; done
manatwork,2012年

多亏了两者。是的,如果我不得不从行中获取这些字符,那么我不妨从整个文件中获取它们。不过,我发现sch的解决方案最能引起轰动。
PSkocik

@manatwork这是一个很好的简单解决方案。即使这样,在我看来,由于某种原因,使用读取循环的上述答案还是要快得多。也许bash中的子字符串相当慢?
krb686 '16

@ krb686,实际上是整个bash“它太大又太慢。” 根据其手册页的“ BUGS”部分。但是,即使这样,在内存中切片字符串仍要比为每个字符一次又一次地读取文件更快。至少在我的机器上:pastebin.com/zH5trQQs
manatwork '16
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.