如何在 bash 中将 `dos2unix` 传送到 `while read`?
How do I pipe `dos2unix` into `while read` in bash?
现在,我正在尝试解决 my PrintBans.sh script 中的一个问题。
问题是,生成这个文件的程序用 \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 传输文件是不可能的吗?
字面答案:通过管道!
如果您不告诉 dos2unix
它正在处理的文件的名称,它就无法就地修改该文件。
while IFS= read -r line; do
echo "No carriage returns here: <$line>"
done < <(dos2unix <"$file")
重定向由 shell 在程序启动前执行 ,当您调用 dos2unix <input.txt
时,shell 替换文件描述符 0在不带参数调用 dos2unix
之前,在 input.txt
上有一个读取句柄。
如果您想成为 真正的 偏执狂(并为这种偏执狂付出性能代价),您可以防止假设不存在的修改文件描述符的 dos2unix通过使它 <(cat <"$file" | dos2unix)
在标准输入上就地接收,这样 dos2unix
正在从连接到单独的可执行文件 cat
的 FIFO 读取,而不是直接从输入文件读取。不用说,我在实践中从来不建议这样做。
更好的答案:不要
您不需要 dos2unix
(它的默认就地修改行为适用于人类交互用户,而不是脚本); shell 本身可以为您剥离 returns:
#!/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}
是一个 parameter expansion,它从变量 var
. 的内容中去除 glob 表达式 expr
的任何尾随实例
$'\r'
是 ANSI C-like string 回车 return 的语法。使用该语法很重要,因为其他看起来像的东西可能指的是马车return 不要.
\r
在任何类型的引用上下文之外只是字母 r
.
"\r"
或 '\r'
是两个字符(一个反斜杠,然后是字母 r
),而不是单个回车符 return.
[[ $line ]]
是bash采用的ksh扩展,相当于[ -n "$line" ]
;它检查变量 line
是否非空。如果您有一个没有任何终止符的部分行,则 read
到 return false 可能仍然填充一行;正如 l0b0 指出的那样,行 separators 而不是 terminators 在 Windows 上很常见。这可确保处理文件的最后一行,即使它没有以换行符结尾。
考虑到您在 github 上的脚本上下文,假设您的 CSV 文件字段的 none 包含一个 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"
...
现在,我正在尝试解决 my PrintBans.sh script 中的一个问题。
问题是,生成这个文件的程序用 \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 传输文件是不可能的吗?
字面答案:通过管道!
如果您不告诉 dos2unix
它正在处理的文件的名称,它就无法就地修改该文件。
while IFS= read -r line; do
echo "No carriage returns here: <$line>"
done < <(dos2unix <"$file")
重定向由 shell 在程序启动前执行 ,当您调用 dos2unix <input.txt
时,shell 替换文件描述符 0在不带参数调用 dos2unix
之前,在 input.txt
上有一个读取句柄。
如果您想成为 真正的 偏执狂(并为这种偏执狂付出性能代价),您可以防止假设不存在的修改文件描述符的 dos2unix通过使它 <(cat <"$file" | dos2unix)
在标准输入上就地接收,这样 dos2unix
正在从连接到单独的可执行文件 cat
的 FIFO 读取,而不是直接从输入文件读取。不用说,我在实践中从来不建议这样做。
更好的答案:不要
您不需要 dos2unix
(它的默认就地修改行为适用于人类交互用户,而不是脚本); shell 本身可以为您剥离 returns:
#!/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}
是一个 parameter expansion,它从变量var
. 的内容中去除 glob 表达式 $'\r'
是 ANSI C-like string 回车 return 的语法。使用该语法很重要,因为其他看起来像的东西可能指的是马车return 不要.\r
在任何类型的引用上下文之外只是字母r
."\r"
或'\r'
是两个字符(一个反斜杠,然后是字母r
),而不是单个回车符 return.
[[ $line ]]
是bash采用的ksh扩展,相当于[ -n "$line" ]
;它检查变量line
是否非空。如果您有一个没有任何终止符的部分行,则read
到 return false 可能仍然填充一行;正如 l0b0 指出的那样,行 separators 而不是 terminators 在 Windows 上很常见。这可确保处理文件的最后一行,即使它没有以换行符结尾。
expr
的任何尾随实例
考虑到您在 github 上的脚本上下文,假设您的 CSV 文件字段的 none 包含一个 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"
...