【问题标题】:Bash: redirect `cat` to file without newlineBash:将`cat`重定向到没有换行符的文件
【发布时间】:2023-03-22 03:40:01
【问题描述】:

我确信这个问题已经在某个地方得到了回答,但是在搜索它时,我找不到我的确切情况。我有两个文件要连接成一个文件,但我还在两个文件之间添加用户输入。问题是在第一个文件之后插入了一个换行符,其余部分按需要工作。

touch newFile
cat file1 > newFile
echo -n $userInput >> newFile
cat file2 >> newFile

当 file1 添加到 newFile 时,如何防止或删除换行符?如果我cat file1 似乎有一个由cat 添加的换行符,但我看到的关于cat 的所有内容都说它没有这样做。如果我vim file1 文件末尾没有空行表明换行符是文件的一部分,那么cat 实际上是在添加换行符,或者重定向> 正在这样做,或者echo 在其输出的开头添加了一个换行符,在这种情况下没有一个是可取的。我看到的一种解决方案是使用

cat file1 | tr -d '\n'

但这会丢弃文件中的所有换行符,这也是不可取的。所以,重复我的问题:

我如何cat file1 进入新文件并添加用户输入而不在它们之间添加换行符?

cat不是必需的,但我对printf不熟悉,所以如果这是解决方案,请详细说明它的使用)。

【问题讨论】:

  • printf '%s' "$userInput"echo -n "$userInput" 更可靠;如果您看到the POSIX spec for echo,您会注意到-n 使行为实现定义,并且标准的APPLICATION USAGE 部分建议printf 代替echo -n 或任何echo 调用反斜杠转义序列。
  • 不知道为什么这个问题被否决了,显然我误解了一些通过进行合理数量的额外研究无法弄清楚的事情,我对我的问题进行了足够的研究以认识到目前的答案不足以回答我的具体问题。通过问这个问题,我学到了很多新东西,因此它达到了它的目的。 @CharlesDuffy 感谢您的帮助和详尽的解释!我不是一个完整的 BASH/UNIX 菜鸟,但我还有很多东西要学。

标签: linux bash command-line newline cat


【解决方案1】:

使用这些输入:

userInput="Test Test Test"

echo "Line 1
Line 2
Line 3" >file1

echo "Line 4
Line 5
Line 6" >file2

我愿意:

printf "%s%s%s" "$(cat file1)" "$userInput" "$(cat file2)" >newfile

>newfile的创建相当于touch在你的第一步添加内容。这样做更容易看出意图。

我明白了:

$ cat newfile
Line 1
Line 2
Line 3Test Test TestLine 4
Line 5
Line 6

【讨论】:

  • 我假设你想要第三个%s,而不是格式字符串中的$s?虽然printf '%s' "$(cat file1)" "$userInput" "$(cat file2)" 会有同样的效果。
  • @CharlesDuffy:是的,谢谢,但奇怪的是它仍然有效!
  • 当变量为空时,它的工作方式与%s%s%s 相同——当占位符用完时重复格式字符串。当s 不为空时,事情会很有趣。 :)
  • 太棒了,这绝对是一个更清洁的解决方案,谢谢!
【解决方案2】:

与所有其他 Unix 工具一样,Vim 将 \n 视为行终止符,而不是行分隔符

这意味着在最后一段文本之后的换行将被视为最后一行的一部分,并且不会显示额外的空白行。

如果没有尾随换行符,Vim 将在文件加载时在状态栏中显示[noeol]

foo
~
~
~
~
~
"file" [noeol] 1L, 3C            1,1           All
        ^---- Here

所以不,换行符绝对是文件的一部分,不会以任何方式被 bash 添加。

如果你想去除所有尾随换行符,你可以这样做作为命令扩展的副作用:

printf '%s' "$(<file1)" >> newfile

【讨论】:

  • 这解释了很多,谢谢!我没有意识到 VIM 会像那样“隐藏”换行符,所以我的问题是基于对换行符的来源的误解。
  • 我在这个答案和我选择的答案之间,但另一个有更优雅的解决方案,但如果没有这个答案,我仍然会对整个 VIM 事情感到困惑。所以应该添加一个功能来选择多个答案组合作为解决方案:)
【解决方案3】:
touch newFile
echo -n "$(cat file1)" > newFile
echo -n $userInput >> newFile
cat file2 >> newFile

成功了。

【讨论】:

  • 三重反引号是 GitHub 对 Markdown 的补充——它们不是基线语法的一部分,并且不受 StackOverflow 解析器的支持。使用由{} 按钮创建的四空格缩进,用于多行代码格式;这也启用了语法高亮,这是反引号包围的内容没有得到的。
  • ...说的是内容而不是形式——实际上,您是在删除文件中存在的一行;这是因为$(...)... 的输出中删除了最后一个换行符——因此您的输出中的换行符比输入文件少;您不会在没有添加换行符的情况下传递内容,而是在执行此操作时主动删除换行符。
  • (另外,你当然想要"$userInput",而不是$userInput,除非你想用运行代码的目录中的文件名列表替换*;参见@987654321 @)。
  • @CharlesDuffy 再次感谢所有这些解释,我一直在使用 Slack,以至于我使用了习惯力量的三次反引号。 ......现在为什么“$(...)”实际上以它的方式工作也更有意义了。在 VIM “隐藏”换行符和 $(...) 删除换行符之间,我对我目睹的行为感到非常困惑。感谢您解释它是如何工作的! (现在,是时候真正学习 printf 了,显然这是我现在应该知道的)
猜你喜欢
  • 1970-01-01
  • 2011-06-11
  • 1970-01-01
  • 2014-10-17
  • 2015-11-30
  • 2011-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多