1

现在,我正在尝试解决我的 PrintBans.sh 脚本中的问题。

问题是,生成这个文件的程序用 \r\n 行结尾保存它,所以我需要while循环能够读取 \r\n 行,否则在最后一行的末尾会有一个额外的 \r导致算术失败:

 - 621355968000000000")syntax error: invalid arithmetic operator (error token is "

这些我都试过了。

while read ban
do
    ...
done < dos2unix $file

while read ban
do
    ...
done < `dos2unix $file`

cat $file > dos2unix > while read ban
do
    ...
done

while read ban
do
    ...
done < dos2unix < $file

我也看到有些人设置了IFS='\r\n',但这对我不起作用。

在不覆盖原始文件的情况下,是否无法通过 dos2unix 传输文件?

4

2 回答 2

6

字面答案:管道通过!

如果您不告诉dos2unix它正在使用的文件的名称,它就无法就地修改该文件。

while IFS= read -r line; do
  echo "No carriage returns here: <$line>"
done < <(dos2unix <"$file")

重定向由 shell在程序启动之前执行,当您调用 时 ,shell 在 不带参数的调用之前dos2unix <input.txt将文件描述符 0 替换为读取句柄 on 。input.txtdos2unix

如果您想真正偏执(并为这种偏执付出性能成本),您可以防止假设的不存在的 dos2unix 修改了在 stdin 上接收到的文件描述符就地修改<(cat <"$file" | dos2unix),例如dos2unix从 FIFO 读取连接到单独的可执行文件cat,而不是直接来自输入文件。不用说,我从不建议在实践中这样做。


更好的答案:不要

你不需要dos2unix(它 - 具有默认的就地修改行为 - 用于人类交互用户,而不是脚本);外壳本身可以为您去除回车:

#!/usr/bin/env bash
#              ^^^^- not /bin/sh; needed for $'' syntax and [[ ]]

while IFS= read -r line || [[ $line ]]; do
  line=${line%$'\r'}
  echo "No carriage returns here: <$line>"
done <"$file"
  • ${var%expr}是一个参数扩展expr,它从变量的内容中去除 glob 表达式的任何尾随实例var
  • $'\r'是用于回车的类似 ANSI C 的字符串语法。使用该语法很重要,因为其他看起来可能引用回车的东西却没有

    • \r在任何类型的引用上下文之外只是字母r
    • "\r"或者'\r'是两个字符(一个反斜杠,然后是字母r),而不是一个回车符。
  • [[ $line ]]是 bash 采用的 ksh 扩展,相当于[ -n "$line" ]; 它检查变量line是否为非空。如果您的部分行没有任何终止符,则可以read在填充行的同时返回 false;正如 l0b0 指出的那样,行分隔符而不是终止符在 Windows 上很常见。这可以确保处理文件的最后一行,即使它没有以换行符结尾。
于 2018-10-06T20:14:07.253 回答
0

考虑到 github 上脚本的上下文,假设 CSV 文件的所有字段都不包含 CR 字符,您只需将 CR 放入IFS.

改变:

while read ban; do ...

至:

while IFS=$'\r' read -r ban; do ...

以相同的价格,您可以将禁令拆分为六个字段:

while IFS=$';\r' read -r name idip end_time reason admin start_time remaining; do
    name=${name/,/\\,}
    ticksToDateString "$end_time"
    ...
于 2018-10-06T21:55:59.750 回答