Sol*_*osa 11 shell-script text-processing
假设我有一个direction
包含以下行的文件
east
north
south
west
south-west
Run Code Online (Sandbox Code Playgroud)
并使用循环并echo
在 shell 脚本中生成以下输出:
Direction: east
Direction: north
Direction: south
Direction: west
Last direction: south-west
Run Code Online (Sandbox Code Playgroud)
换句话说,我想对脚本中的最后一行做一些不同的事情。
cas*_*cas 22
bash
无法检测文件的结尾(不尝试读取下一行并失败),但 perl 可以使用其eof
功能:
$ perl -n -e 'print "Last " if eof; print "Direction: $_"' direction
Direction: east
Direction: north
Direction: south
Direction: west
Last Direction: south-west
Run Code Online (Sandbox Code Playgroud)
注意:与echo
bash 不同,print
perl 中的语句不会打印换行符,除非您 1. 通过包含\n
在要打印的字符串中明确告诉它,或者 2. 使用 perl 的-l
命令行选项,或者 3. if字符串已经包含换行符......就像$_
- 的情况一样,这就是为什么你经常需要chomp()
它来删除换行符。
BTW,在 perl 中,$_
是当前输入行。或者任何未指定实际变量名称的循环中的默认迭代器(通常称为“当前事物”,可能是因为“dollarunderscore”有点拗口)。如果未提供,许多Perl 函数和运算符将用作默认/隐式参数。$_
查看man perlvar
并搜索$_
.
sed
也可以 -$
地址与文件的最后一行匹配:
$ sed -e 's/^/Direction: /; $s/^/Last /' direction
Direction: east
Direction: north
Direction: south
Direction: west
Last Direction: south-west
Run Code Online (Sandbox Code Playgroud)
规则的顺序sed
很重要。我的第一次尝试以错误的方式进行了(并打印了“方向:最后的西南方向”)。此 sed 脚本始终将“Direction:”添加到每行的开头。在最后一行 ( $
) 中,它将“Last ”添加到已被前一条语句修改的行的开头。
ter*_*don 16
循环无法知道何时到达终点,除非它确实到达终点。因此,要么处理文件两次,一次获取行数,另一次输出,或者打印每次迭代时的前一个值和退出循环时的最后一个值:
prev=""
while read direction; do
if [ -n "$prev" ]; then
echo "Direction: $prev"
fi
prev="$direction"
done < direction
echo "Last Direction: $prev"
Run Code Online (Sandbox Code Playgroud)
Nic*_*teo 10
FelixJN 的答案的一个变体,将行读入数组,但使用 bash 内置函数而不是 bash 循环:
mapfile -t DIR < direction
printf "Direction: %s\n" "${DIR[@]::${#DIR[@]}-1}"
printf "Last direction: %s\n" "${DIR[-1]}"
Run Code Online (Sandbox Code Playgroud)
mapfile是 Bash 4 中添加的内置函数,它将标准输入读取到数组中,每个条目一行。该-t
选项会去除换行符。
printf
将重复应用其格式字符串,直到用完所有输入参数。
您可以将值读入数组,然后使用数组长度:
#!/bin/bash
i=0
while read line ; do
arr[$i]="$line"
((i++))
done <file
for (( i=0 ; i<=${#arr[@]}-2 ; i++ )) ; do
echo Direction: ${arr[i]}
done
echo Last direction: ${arr[-1]}
Run Code Online (Sandbox Code Playgroud)
当然,这意味着所有数据都在 RAM 中。
arr=( $(cat file) )
仅当行条目没有空格时,更简单的方法才有效,因此我while read
在这里使用了 -loop 。
您可以混合使用paste
,tail
和head
:
$ paste -s -d'\n' <(head -n -1 direction | sed 's/^/Direction: /') <(tail -n1 direction | sed 's/^/Last direction: /')
Direction: east
Direction: north
Direction: south
Direction: west
Last direction: south-west
Run Code Online (Sandbox Code Playgroud)
paste -s -d'\n'
使用换行符作为分隔符-d'\n'
,并带有选项 和 选项-s
:
-s, --serial
一次粘贴一个文件而不是并行粘贴
head -n -1
检索除最后一行之外的所有行,然后通过管道传输到sed
仅在这些行中执行您需要的命令。
tail -n1 file
检索文件的最后一行,然后通过管道传输到sed
仅执行该行中所需的命令。
或者更简洁地只是使用cat
而不是paste
,正如@Mick Matteo 的评论所指出的:
$ cat <(head -n -1 direction | sed 's/^/Direction: /') <(tail -n1 direction | sed 's/^/Last direction: /')
Run Code Online (Sandbox Code Playgroud)