【问题标题】:CAT ignores newline characterCAT 忽略换行符
【发布时间】:2021-06-17 09:16:54
【问题描述】:

我是一名学习者,我刚刚创建了一个新的 bash 脚本,它从命令行读取两个文件名并将它们的内容连接起来打印。但是,它不起作用。我有两个文件:log1.txt 和 log2.txt,它们都以换行符结尾。我的代码基本上是这样的:

 File+=$(cat "$first")
 File+=$(cat "$second")
 echo "$File"

但是,第一个文件的结尾和第二个文件的开头合并在一行中。我该如何解决?我已经在谷歌上搜索了几个小时,如果有任何帮助,我将不胜感激。

【问题讨论】:

  • 命令替换的记录、正常、预期、开箱即用的行为是删除任何尾随换行符。
  • 顺便说一句,也许你想要File=$(<"$first")$'\n'$(<"$second")?仅限 Bash,但执行速度要快得多(不需要任何 /usr/bin/cat 可执行文件,但仅使用 shell 的内置函数运行)。
  • ...要明确:这不是cat 删除你的换行符。是命令替换 -- $(...) -- 修剪它们,即使 cat 包含它们。

标签: bash newline


【解决方案1】:

命令替换会修剪命令运行输出中的任何尾随换行符。这种行为是 POSIX 标准规定的——否则它没有任何意义,因为 POSIX 规定 UNIXy 系统上的 所有 有效文本行必须以换行符终止;因此,如果不是这样,人们将需要不断修剪尾随的换行符。


但是,您没有理由将引入该换行符作为您的 shell 的问题:

cat 代表“连接”;当给定多个文件时,它将它们连接在一起。如果您不传递多个参数,则通常没有充分的理由首先使用它。

File=$(cat "$first" "$second")

【讨论】:

  • 文件数量不等,我写的只是一个例子。我在 $@ 中运行一个 for 循环,对于每个文件,我想将它添加到现有文件中。那是我的问题
  • File+=$'\n'"$(<"$file")",然后。
  • ...或者更好,读入一个数组,而不是一个字符串。 for file in "$@"; do Files+=( "$(<"$file")" ); done
  • ...然后你可以printf '%s\n' "${Files[@]}" 一次发射所有内容。
  • 您也可以Files=$(cat -- "$@") 一次性完成所有操作,只需将所有文件名传递给cat,根本不需要在 bash 中循环它们。
【解决方案2】:

Command substitutions 从内部的复合命令中删除标准输出末尾的任何尾随换行符(甚至是多个换行符)。解决此问题的两种主要方法是

  1. 确保命令替换以其他终结符结尾,然后删除或
  2. 使用命令替换以外的东西。

第一个的简单实现是这种模式:

name="$(some_command; echo x)"
name="${name%x}"

避免命令替换的最简单方法是将每个文件连接到一个单独的文件:

cleanup() {
    if [[ -d "$work_dir" ]]
    then
        rm --force --recursive "$work_dir"
    fi
}
trap cleanup EXIT
work_dir="$(mktemp --directory)"
aggregate_file="${work_dir}/aggregate"
cat "$first" > "$aggregate_file"
…

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-01
    • 2020-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多