【问题标题】:Reading character by character with android shell (mksh)使用 android shell (mksh) 逐字符读取
【发布时间】:2018-06-18 07:55:45
【问题描述】:

对不起,如果问题很简单。我是 shell 脚本的初学者,我需要编写一个脚本,它可以在安装了 mksh 的机器上的文本文件上运行,但没有 sed 或大多数 gnu 实用程序的工作版本或兼容。

也没有安装dos2unix的版本。

脚本接收一个dos格式的文件,但它包含的字符类型非常简单(只有字母和数字,每行长度低于20个字符,少于1000行),它读取文件字符通过字符将字符添加到“行”变量。当它到达回车时,它会打印该行。用法将是 sh script.sh file.txt > newfile.txt。

脚本没有按预期工作,我不确定为什么:

#!/bin/sh

riga="";

nomefile="$1";

while IFS='' read -r -n1 carattere; 
    do 
        if [[ $carattere !=  *$'\r'* ]]; then
           riga="${riga}carattere";
        elif [[ $carattere == *$'\r'* ]]; then
            print "${riga%$}";
            riga="";
        fi    



done < "$nomefile"

这是最初编写的脚本的输出:

caratterecaratterecaratterecaratterecaratterecaratterecaratterecaratterecarattere
caratterecaratterecaratterecaratterecaratterecaratterecaratterecaratterecarattere
caratterecaratterecaratterecaratterecaratterecaratterecaratterecaratterecarattere
caratterecaratterecaratterecaratterecaratterecaratterecaratterecaratterecarattere
caratterecaratterecaratterecaratterecaratterecaratterecaratterecaratterecarattere
caratterecaratterecaratterecaratterecaratterecaratterecaratterecaratterecarattere
caratterecaratterecaratterecaratterecaratterecaratterecaratterecaratterecarattere
caratterecaratterecaratterecaratterecaratterecaratterecaratterecaratterecarattere
caratterecaratterecaratterecaratterecaratterecaratterecaratterecaratterecarattere

我在https://www.freebsd.org/cgi/man.cgi?query=ksh阅读了ksh的优秀手册页并修改了脚本如下:

#!/bin/sh

#!i=0
#!
riga="";

nomefile="$1";

while IFS='' read -r -n1 carattere; 
    do 
        if [[ $carattere !=  *$'\r'* ]]; then
           riga="${riga}$carattere";
        elif [[ $carattere == *$'\r'* ]]; then
            print "${riga%$}";
            riga="";
        fi    



done < "$nomefile"

输出与我的意图相似,但在打印行之间插入了空白行:

ID

1

2

3

4

5

6

7

8

【问题讨论】:

  • 您不能在以sh 运行的脚本中使用[[ ]],它只知道[ ]。此外,您似乎有错误的重定向方式;使用&lt; "$nomefile" 从该文件中读取。您是否仅限于 sh,或者 Bash 可用?
  • 脚本运行在mksh中,这是系统中唯一的shell。 [[ ]] 被这个特定的 shell 正确解释,因为我有另一个脚本在其中使用它们(并且这个脚本没有使用单括号运行)。你对重定向是正确的,我正在纠正这个。
  • 哦,好的。您的问题是“Bourne shell”,它是一种古老的外壳,已不再在任何地方使用,您可能应该澄清这一点并至少添加 ksh 标签而不是 sh
  • 我澄清了平台并按照建议更改了标签。对 bourne shell 和 sh 标记的引用是有意的,因为我认为我会安全地坚持 sh 兼容性(而不是仅使用 bash 语法):您对双括号的评论让我认为情况并非如此(我认为如您所写,bourne shell 不会解释双括号,因此 mksh 并不真正兼容)。

标签: android shell text ksh


【解决方案1】:

好的,在阅读了更多的 ksh 手册页和一些测试之后,我发现了什么不起作用。我的脚本的第一个版本没有正确地将我读取的字符附加到 riga 变量,因为我没有使用替换 ($) 来附加 carattere 变量。

第二个版本按预期工作,但没有考虑到 dos 文件以 CRLF 终止行的事实:因此我正在检查 \r 字符,这意味着 \n 字符已添加到我的 riga 变量。我修改了第一个 if 条件以检查字符是否也与 \n 不同。

然后我的脚本中的另一个问题是,在我要转换的文件结构中,有 n 行并且最后一行没有终止。这意味着我的脚本不会在 riga 变量中写入最后一行的字符,但它不会打印最后一行。我解决了这个在while循环后添加打印指令的问题,使用-n参数避免在字符串后打印换行符。

脚本的最终版本是:

#!/bin/sh

#!i=0
#!^M
riga="";

nomefile="$1";

while IFS='' read -r -n1 carattere; 
    do 
        if [[ $carattere !=  *$'\r'* ]] && [[ $carattere !=  *$'\n'* ]]; then
           riga="${riga}$carattere";
        elif [[ $carattere == *$'\r'* ]]; then
            print "${riga%$}";
            riga="";
        fi    



done < "$nomefile"

print -n "${riga%$}";

感谢 Benjamin,他的 cmets 让我找到了正确的方向来解决我的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 2019-07-11
    • 1970-01-01
    相关资源
    最近更新 更多