我在使用命令连接文件时遇到了一个奇怪的问题cat
。我有两个文件,每个文件中都有一个字符串:
文件1:
ABC
文件2:
DEF
要么我做cat file1 file2
,要么我做cat file1 >> file2
。我期望输出如下所示:
ABC
DEF
但是,我有一个有趣的输出,如下所示:
ABCDEF
我检查了文件,没有多余的空格或字符。但是,当我从字符串后面手动删除时,我什至看不到单个字符。效果很好。我想一定有某种我看不到的“隐藏”字符或线条。
它一直困扰着我,因为我有大量文件需要连接。我无法手动做同样的事情。
任何帮助表示赞赏。
答案1
paste
可能是最简单的(更不用说非常高效了)意味着您可以处理这个问题。
printf abc >file1
printf def >file2
paste -sd\\n file[12]
abc
def
当paste
串行调用时-s
,它将依次读取每个命名输入文件以及paste
每个文件中 <tab> 或指定分隔符字符串上每一行的输出-d
。虽然paste
总是以 ewline 结束每个命名 infile 的输出\n
,但这里的-d
分隔符也被指定为\n
ewline,因此它基本上只是cat
将其输入输出,但每个文件总是以\n
ewline 结尾。
正如 Peter 在下面指出的,空文件可能会导致paste
发出额外的\n
ewline。如果这是一个问题,实际上可以应用相同的sed
方法不是这样做:
: > file0
sed '' file[012]
abc
def
不过现在用这个方法,sed
(至少有 GNU )可能有不同的问题。任何sed
意愿总是在拉入另一行之前先写出一条\n
ewline,但如果是非常整个串联输入文件系列的最后一行,然后是一些sed
s(例如 GNU)可能不是在末尾添加一个换行符。例如,对于我的输入文件,定义后面没有换行符。
而如果那是一个问题,嗯...
sed '' file[012] | paste -sd\\n
...上述管道可能应该涵盖您的所有基础。
答案2
正如彼得所说,您的第一个文件没有行尾字符。您也许可以用ls -l
--- 检查它,如果它恰好是三个字符,那就是它。
如果你想“cat”文件并添加换行符仅有的如果换行符不存在,您可以使用解释的好技巧这里。
如果你有这三个文件:
[romano:~/tmp] % ls -l f1 f2 f3
-rw-rw-r-- 1 romano romano 3 Jul 12 14:58 f1
-rw-rw-r-- 1 romano romano 4 Jul 12 15:03 f2
-rw-rw-r-- 1 romano romano 4 Jul 12 15:03 f3
[romano:~/tmp] % cat f1 f2 f3
ABCDEF
GHI
其中f1
最后一行没有行尾,而其他行有,你可以这样做:
[romano:~/tmp] % sed -e '$a\' f1 f2 f3
ABC
DEF
GHI
...sed
是一个流编辑器,您指示它打印所有未更改的内容,最后一行不添加任何内容 --- 但sed
在操作时隐式添加换行符,因此它解决了问题。
请注意,仅使用cat
+echo
就会添加换行符总是。这样你就有了两个:
[romano:~/tmp] % for i in f?; do cat $i; echo; done;
ABC
DEF
GHI
[romano:~/tmp] %
答案3
看来你file1
没有尾随换行符。如果您想连接文件列表。您可以先检查每一项,并cat
在需要时检查换行符,如下所示:
# make some sample files
printf "%s\n" abc > file1
printf "%s" def > file2 # no trailing newline
printf "%s\n" ghi > file3
printf "%s" jkl > file4 # no trailing newline
# find files to concatenate and build a sorted array `f[]`
unset f i;
while IFS= read -r -d $'\0' path; do f[i++]="$path"
done < <(find . -type f -name 'file[0-9]' -print0 | sort -z)
# build the `cat` command
cmd=cat
tmp="$(mktemp)"; echo >$tmp # a file which contains only `\n`
for file in "${f[@]}"; do
lasthex=$(tail -c1 $file | hexdump -ve '1/1 "%02x"')
[[ -z $lasthex ]] && continue # skip enpty files
[[ $lasthex == 0a ]] && nl= || nl=" $tmp"
cmd="$cmd \"$file\"$nl"
done
# execute the `cat` command
eval "$cmd"
连接的结果是:
abc
def
ghi
jkl
生成的命令是:
cat "./file1" "./file2" /tmp/tmp.z7iKccY0T9 "./file3" "./file4" /tmp/tmp.z7iKccY0T9
答案4
您可以在文件中看到特殊字符od -c filename
。换行符看起来像\n
.如果 Windows 或源代码管理更改了换行符,您将看到\r\n
using od -c
,但不会看到任何与 不同的内容cat
。您可以用来dos2unix filename
修复这些。
有时您会看到 cat 打印出的一系列控制字符,看起来像“-”或其他有效字符。