如何在 shell 脚本中提取字符串的前两个字符?

例如:

USCAGoleta9311734.5021-120.1287855805

我只想提取:

US
334885 次浏览

最简单的方法是:

${string:position:length}

其中在 $position处从 $string提取 $length子字符串。

这是一个内置的 Bash,所以 awk 或 sed 不是必需的。

如果您正在使用 bash shell (根据您的注释,您似乎正在使用它) ,那么最有效的方法可能是使用参数展开的子字符串变体:

pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}" ; echo "${short}"
US

这将把 short设置为 long的前两个字符。如果 long小于两个字符,则 short将与之相同。

如果您要经常使用这种内部 shell 方法(比如您提到的每个报告执行50,000次) ,那么这种方法通常会更好,因为不需要进程创建开销。所有使用外部程序的解决方案都将受到这种开销的影响。

如果你也想确保 最低限度的长度,你可以在手之前用类似这样的东西来填充它:

pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}" ; echo "${short}"
A.

这将确保任何长度小于两个字符的内容都在右侧用句点填充(或其他内容,只需更改创建 tmpstr时使用的字符)。还不清楚你是否需要这个,但我想我应该把它完整地放进去。


尽管如此,有很多方法可以用外部程序实现这一点(例如,如果您没有可用的 bash) ,其中一些方法是:

short=$(echo "${long}" | cut -c1-2)
short=$(echo "${long}" | head -c2)
short=$(echo "${long}" | awk '{print substr ($0, 0, 2)}'
short=$(echo "${long}" | sed 's/^\(..\).*/\1/')

前两个字符(cuthead)对于单行字符串是相同的-它们基本上都只返回前两个字符。它们的不同之处在于,cut将给出每行的前两个字符,而 head将给出整个输入的前两个字符

第三个使用 awk子字符串函数提取前两个字符,第四个使用 sed捕获组(使用 ()\1)捕获前两个字符并用它们替换整行。它们都类似于 cut——它们提供输入中每行的前两个字符。

如果您确定输入是一行,那么所有这些都无关紧要,因为它们都具有相同的效果。

这可能就是你想要的:

my $string = 'USCAGoleta9311734.5021-120.1287855805';


my $first_two_chars = substr $string, 0, 2;

参考资料: 字幕

密码

if mystring = USCAGoleta9311734.5021-120.1287855805


print substr(mystring,0,2)

印刷美国。

其中0是开始位置,2是要读取的字符数。

perl -ple 's/^(..).*/$1/'

你已经得到了几个很好的答案,我会选择内置的 Bash,但是因为你问了关于 sedawk以及(差不多)没有其他人提供基于它们的解决方案,我给你这些:

echo "USCAGoleta9311734.5021-120.1287855805" | awk '{print substr($0,1,2)}'

还有

echo "USCAGoleta9311734.5021-120.1287855805" | sed 's/\(^..\).*/\1/'

awk版本应该是相当明显的,但下面是对 sed版本的解释:

  • 用“ s/”代替
  • 任意两个字符组成的“()”。从“ ^”开始,后跟任何字符重复0次或更多次“ *”(需要反斜杠来转义一些特殊字符)
  • 通过“/”表示第一个(在本例中也是唯一的)组的内容(这里的反斜杠是一个特殊的转义符,指向一个匹配的子表达式)
  • 完成”/

Colrm ーー从文件中删除列

要保留前两个字符,只需删除从3开始的列

cat file | colrm 3

如果你在 bash,你可以说:

bash-3.2$ var=abcd
bash-3.2$ echo ${var:0:2}
ab

这可能正是你需要的。

用途:

sed 's/.//3g'

或者

awk NF=1 FPAT=..

或者

perl -pe '$_=unpack a2'

只要格雷普:

echo 'abcdef' | grep -Po "^.."        # ab

如果您的系统使用不同的 shell (而不是 bash) ,但是您的系统有 bash,那么您仍然可以通过使用变量调用 bash来使用 bash固有的字符串操作:

strEcho='echo ${str:0:2}' # '${str:2}' if you want to skip the first two characters and keep the rest
bash -c "str=\"$strFull\";$strEcho;"

如果您希望使用 shell 脚本,而不是依赖于非 posix 扩展(比如所谓的 bashism) ,那么可以使用不需要分支外部工具(如 grep、 sed、 cut、 awk 等)的技术,这会降低脚本的效率。也许效率和 posx 可移植性在您的用例中并不重要。但是,如果是(或者仅仅是一个好习惯) ,您可以使用以下 参数展开选项方法来提取 shell 变量的前两个字符:

$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab

这将使用 “最小前缀”参数展开删除前两个字符(这是 ${var#??}部分) ,然后使用 “最小后缀”参数扩展(${var%部分)从原始值中删除除了前两个字符以外的所有字符串。

这个方法之前在这个 回答中被描述为“ Shell = Check if 變量以 # 开头”问题。这个答案还描述了两个类似的参数展开方法,这些方法可以用在稍微不同的上下文中,与这里应用于原始问题的方法不同。

你可以使用 printf:

$ original='USCAGoleta9311734.5021-120.1287855805'
$ printf '%-.2s' "$original"
US

只是为了好玩,我还要补充几点,尽管它们过于复杂和无用,但没有被提及:

head -c 2 <( echo 'USCAGoleta9311734.5021-120.1287855805')


echo 'USCAGoleta9311734.5021-120.1287855805' | dd bs=2 count=1 status=none


sed -e 's/^\(.\{2\}\).*/\1/;' <( echo 'USCAGoleta9311734.5021-120.1287855805')


cut -c 1-2 <( echo 'USCAGoleta9311734.5021-120.1287855805')


python -c "print(r'USCAGoleta9311734.5021-120.1287855805'[0:2])"


ruby -e 'puts "USCAGoleta9311734.5021-120.1287855805"[0..1]'

如何考虑 Unicode + UTF-8

让我们对那些对 Unicode 字符而不仅仅是字节感兴趣的字符进行一个快速测试。áéíóú(尖锐的重音元音)的每个字符由 UTF-8中的两个字节组成。配合:

printf 'áéíóú' | LC_CTYPE=en_US.UTF-8 awk '{print substr($0,1,3);exit}'
printf 'áéíóú' | LC_CTYPE=C awk '{print substr($0,1,3);exit}'
printf 'áéíóú' | LC_CTYPE=en_US.UTF-8 head -c3
echo
printf 'áéíóú' | LC_CTYPE=C head -c3

我们得到:

áéí
á
á
á

所以我们看到只有 awk + LC_CTYPE=en_US.UTF-8考虑 UTF-8字符。其他方法只需要三个字节。我们可以通过以下方式证实:

printf 'áéíóú' | LC_CTYPE=C head -c3 | hd

它给出了:

00000000  c3 a1 c3                                          |...|
00000003

c3本身就是垃圾,不会出现在终端上,所以我们只看到了 á

然而,awk + LC_CTYPE=en_US.UTF-8实际上返回6个字节。

我们也可以用以下方法进行同样的测试:

printf '\xc3\xa1\xc3\xa9\xc3\xad\xc3\xb3\xc3\xba' | LC_CTYPE=en_US.UTF-8 awk '{print substr($0,1,3);exit}'

如果你想要一个通用参数:

n=3
printf 'áéíóú' | LC_CTYPE=en_US.UTF-8 awk "{print substr(\$0,1,$n);exit}"

关于 Unicode + UTF-8: https://superuser.com/questions/450303/unix-tool-to-output-first-n-characters-in-an-utf-8-encoded-file的具体问题

相关阅读: https://unix.stackexchange.com/questions/3454/grabbing-the-first-x-characters-for-a-string-from-a-pipe

在 Ubuntu 21.04上测试。