从cat命令中获取前X个字符?


42

我有一个文本文件,正在我的shell脚本中输出到一个变量。我只需要前50个字符。

我已经尝试过使用,cat ${filename} cut -c1-50但是我获得的不仅仅是前50个字符了吗?这可能是由于cut寻找行(不是100%确定),而此文本文件可能是一个长字符串-确实取决于。

是否可以使用实用程序从cat命令中获取前X个字符?


10
你忘了|吗?cat ${filename} | cut -c1-50
DisplayName 2014年

@DisplayName已修复,感谢您捕获我的重新输入错误。
jkj2000

1
@ jkj2000,我已恢复为较早版本,因为这是原始问题。
Ramesh 2014年

Answers:


61
head -c 50 file

这将返回前50个字节。

请注意,并非在所有OS上都始终执行相同的命令。在Linux和macOS上,它的行为是这样的。在Solaris(11)上,您需要在/ usr / gnu / bin /中使用gnu版本


没有-c选择。我会选择dd(1)代替。
mirabilos 2014年

7
请注意,此答案假定文件仅包含ASCII字符,因为OP要求输入前X个字符,而不是字节。
Calimo 2014年

2
@mirabilos它可能不是可移植的,但是我的版本(GNU coreutils 5.97)可以移植。
Yossarian 2014年

1
POSIX并未定义-c为有效选项,因此它绝对取决于您的本地环境。unix.com/man-page/posix/1/head
Jules,

1
@Calimo是的,我知道,但是我尝试制作一个100个字符的文本文件,然后运行我的命令,它打印了50个字符。但是您对ASCII的看法是正确的,但是由于OP将其标记为已回答,因此在他的情况下没有任何答案。
DisplayName 2014年

27

cut如果您使用管道将数据传递给它,那么您的命令将起作用:

cat ${file} | cut -c1-50 

或者,避免不必要地使用猫,并使其更安全一些:

cut -c1-50 < "$file"

请注意,上述命令将打印每行输入的前50个字符(或字节,具体取决于您的cut实现)。如您所说,如果您的文件占了很大的一行,它应该达到您的期望。


8
dd status=none bs=1 count=50 if=${filename}

这将返回前50个字节。


dd没有status=none标志。使用2>/dev/null代替(并正确引用):(dd if="$filename" bs=1 count=50 2>/dev/null即使如此,也可以考虑使用bs=50 count=1来减少所涉及的syscall数量)。
mirabilos 2014年

1
status=none在使用Ubuntu 14.04,coreutils 8.21时,@ mirabilos dd确实存在,但是2>/dev/null如果使用早期版本,则使用是正确的。
doneal24 2014年

1
@mirabilos大多数Linux发行版都使用GNU coreutils,就像FreeBSD和其他BSD一样。它在Solaris上作为软件包gnu-coreutils提供。是的,这是“ Unix&Linux”,Unix和Linux系统都使用GNU coreutils。
doneal24

2
不,Unix系统通常不使用GNU实用程序。GNU甚至是“ GNU不是Unix”的首字母缩写。请坚持使用便携式解决方案,或者,如果您必须提供仅GNU的解决方案,请说明,并尽可能显示等效的便携式解决方案。
mirabilos 2014年

1
严格来说,这read()是50字节之一。file例如,如果管道,并且此时可用的字符较少,则将返回较少的字节。要具有等同的功能head -c50,您需要使用特定的GNU iflag=fullblock
斯特凡Chazelas

4

到目前为止,大多数答案都假定1个字节= 1个字符,如果使用的是非ASCII语言环境,则可能不是这种情况。

一种更强大的方法:

testString=$(head -c 200 < "${filename}") &&
  printf '%s\n' "${testString:0:50}"

请注意,这假定:

  1. 您正在使用ksh93bash(或最新的zshmksh(尽管受支持的唯一多字节字符集mksh是UTF-8,并且仅在之后set -o utf8-mode))和head支持的版本-c(目前大多数情况下都在使用,但严格来说不是标准的)。
  2. 当前语言环境设置为与文件相同的编码(键入locale charmapfile -- "$filename"检查);如果没有,请使用ie进行设置。LC_ALL=en_US.UTF-8
  3. head假设使用最坏情况的UTF-8,其中所有字符最多编码为4个字节,因此使用来获取文件的前200个字节。这应该涵盖我能想到的大多数情况。

当然,这也假定使用GNU head或它的另一个实现,其中添加了nōn-standard -c选项。但是您已经需要GNU bash。(请注意:mkshUTF-8模式可以对UTF-8编码的文件执行此操作。)我会问OP是否需要八位字节或多字节字符,只是“字符”是一个模糊/过时的术语。
mirabilos 2014年

这也假定$filename$testString不包含空白的换行符或通配符或以开头-
斯特凡Chazelas

${var:offset:length}您在此处使用的结构实际上来自(也有自己的)的ksh93最新版本支持。你需要 在和但是。zshzsh$testString[1,50]${testString:0:50}ksh93zsh
斯特凡Chazelas

刚刚编辑了我的答案以解决以上评论
Calimo

2
grep -om1 "^.\{50\}" ${filename}

其他变体(用于文件中的第一行)

(IFS= read -r line <${filename}; echo ${line:0:50})

这是对高级工具的滥用,并且容易发生不想要的事情,例如,如果它们是区域感知的。
mirabilos 2014年

@mirabilos在高级工具下是什么意思:readecho?还是bash expansion
Costas 2014年

grep(regexp),是的,在这里使用shell(提示:第一行可能很大)。(话虽如此,bashism也不在POSIX中,但是大多数shell都实现了。)
mirabilos 2014年

0

1.对于ASCII文件,就像@DisplayName这样说:

head -c 50 file.txt

例如,将打印出file.txt的前50个字符。

2.对于二进制数据,可使用hexdump将其打印为十六进制字符:

hexdump -n 50 -v file.bin

例如,将打印出file.bin的前50个字节。

请注意,如果没有-v详细选项,hexdump则将重复的行替换为星号(*)。请参阅此处:https : //superuser.com/questions/494245/what-does-an-asterisk-mean-in-hexdump-output/494613#494613


-2

您可以为此使用sed,它将很容易解决问题

sed -e 's/^\(.\{50\}\).*/\1/' yourfile

很好奇,如果解决了OP的问题,它会如何被否决:“我只需要前50个字符”就可以完成不使用UUOC(猫的无用使用)的要求
munkeyoto 2014年

1
这个答案给出了文件中每行的前50个字符,而不仅仅是文件的前50个字符。如果所有行的长度都少于50个字符,则也不打印任何内容。您的解决方案将更好地与sed -n -e '1s/^\(.\{50\}\).*/\1/p' ${filename}
doneal24

可以理解的只是:head -n 1 | sed -e's / ^(。\ {50 \})。* / \ 1 /'...这样就可以解决问题。OP指出:“只需要前50个字符”
munkeyoto

1
不。如果第一行只有49个字符,则不会输出任何内容。
doneal24 2014年

道格(Doug)我第一次了解到这一点,但是OP并没有提及如果行中的字符少于50个字符,那么打印就没有提及,所以我仍然看不到您的观点,也没有因此而感到失望,因为它再次陷入了本来可以解决的问题head:head -n 1 $ {文件名} | SED -n -e '1 / ^(\ {50 \}。)* / \ 1 / P。'
munkeyoto
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.