Ber*_*ekz 11 bash array text-processing
我不知道如何让我的代码适用于更多行。
这是原始文件 t.txt:
Hello Earth
Hello Mars
Run Code Online (Sandbox Code Playgroud)
但我得到以下输出:
Mars Hello Earth Hello
Run Code Online (Sandbox Code Playgroud)
我的预期输出是这样的:
Earth Hello
Mars Hello
Run Code Online (Sandbox Code Playgroud)
一般来说,我想保持行序不变,但要颠倒单词。对于一般情况输入将是这样的:
one two
four five
Run Code Online (Sandbox Code Playgroud)
和预期的输出是这样的:
two one
five four
Run Code Online (Sandbox Code Playgroud)
我的代码如下:
#!/bin/bash
text=$(cat $1)
arr=($text)
al=${#arr[@]}
let al="al-1"
while (($al >= 0))
do
echo -n "${arr[al]}"
echo -n " "
let al="al - 1"
done
echo
Run Code Online (Sandbox Code Playgroud)
Ser*_*nyy 19
下面提供的所有示例都适用于行上有任意数量单词的一般情况。基本思想在任何地方都是一样的——我们必须逐行读取文件并反向打印单词。AWK 最好地促进了这一点,因为它已经拥有以编程方式完成的文本处理的所有必要工具,并且是最便携的 - 它可以与任何 awk 衍生产品一起使用,并且大多数系统都拥有它。Python 也有很多很好的字符串处理实用程序,可以让我们完成这项工作。我会说,它是适用于更现代系统的工具。恕我直言,Bash 是最不理想的方法,因为它具有便携性、潜在危险以及需要完成的大量“诡计”。
$ awk '{for(i=NF;i>=1;i--) printf "%s ", $i;print ""}' input.txt
Earth Hello
Mars Hello
Run Code Online (Sandbox Code Playgroud)
它的工作方式相当简单:我们在行上的每个单词中向后循环,打印用空格分隔的单词 - 这是由printf "%s ",$i
函数(用于打印格式化字符串)和 for 循环完成的。NF
变量对应于字段数。默认字段分隔符假定为空格。我们首先i
为单词数设置一个一次性变量,并在每次迭代时递减该变量。因此,如果一行中有 3 个单词,我们将打印字段 $3,然后是 $2 和 $1。最后一次传递后,变量 i 变为 0,条件i>=1
变为假,循环终止。为了防止线条拼接在一起,我们插入一个换行符print ""
。AWK 代码块{}
在这种情况下为每一行处理(如果代码块前面有匹配条件,则取决于要执行的代码块的匹配与否)。
对于那些喜欢替代解决方案的人,这里是 python:
$ python -c "import sys;print '\n'.join([ ' '.join(line.split()[::-1]) for line in sys.stdin ])" < input.txt
Earth Hello
Mars Hello
Run Code Online (Sandbox Code Playgroud)
这里的想法略有不同。<
操作符告诉你当前的 shell 重定向input.txt
到 python 的stdin
流,我们逐行读取。在这里,我们使用列表理解来创建行列表 - 这就是[ ' '.join(line.split()[::-1]) for line in sys.stdin ]
部件所做的。该部分' '.join(line.split()[::-1])
取一行,将其拆分为单词列表,通过 反转列表[::-1]
,然后从中' '.join()
创建一个以空格分隔的字符串。因此,我们有一个更大的字符串列表。最后,'\n'.join()
制作一个更大的字符串,每个项目通过换行符连接。
简而言之,这种方法基本上是一种“打破并重建”的方法。
$ awk '{for(i=NF;i>=1;i--) printf "%s ", $i;print ""}' input.txt
Earth Hello
Mars Hello
Run Code Online (Sandbox Code Playgroud)
并进行测试运行:
$ ./reverse_words.sh
Earth Hello
Mars Hello
Run Code Online (Sandbox Code Playgroud)
Bash 本身没有强大的文本处理能力。这里发生的事情是我们通过以下方式逐行读取文件
while IFS= read -r line
do
# some code
done < text.txt
Run Code Online (Sandbox Code Playgroud)
这是一种常用技术,广泛用于 shell 脚本以逐行读取命令或文本文件的输出。每行都存储到$line
变量中。
在里面我们有
bash -c 'i=$#; while [ $i -gt 0 ];do printf "%s " ${!i}; i=$(($i-1)); done' sh $line
Run Code Online (Sandbox Code Playgroud)
这里我们使用bash
with-c
标志来运行一组用单引号括起来的命令。当-c
使用时,bash
将开始分配命令行参数到变量开始$0
。因为它$0
传统上用于表示程序的名称,所以我sh
首先使用虚拟变量。
$line
由于称为分词的行为,未引用的内容将被分解为单独的项目。分词在 shell 脚本中通常是不可取的,你经常会听到人们说“总是引用你的变量,比如“$foo”。然而,在这种情况下,分词对于处理简单文本是可取的。如果您的文本包含类似的内容$var
,则可能会破坏这种方法。为此,以及其他几个原因,我认为 python 和 awk 方法更好。
至于内码,也很简单:将未加引号的$line
部分拆分成词,传递给内码进行处理。我们获取参数的数量$#
,将其存储到丢弃变量中i
,然后再次 - 使用称为变量间接的东西打印出每个项目 - 这就是${!i}
部分(请注意,这是 bashism - 它在其他 shell 中不可用)。再一次,我们使用printf "%s "
以空格分隔的方式打印出每个单词。完成后,echo
将附加一个换行符。
本质上,这种方法是 awk 和 python 的混合。我们逐行读取文件,但分而治之,使用 的几个bash
功能来完成这项工作。
可以使用 GNUtac
命令完成更简单的变化,并再次使用分词。tac
用于反转输入流或文件的行,但在这种情况下,我们指定-s " "
使用空格作为分隔符。因此,var
将包含一个以相反顺序以换行符分隔的单词列表,但由于$var
没有被引用,换行符将被替换为空格。诡计,再次不是最可靠的,但有效。
#!/bin/bash
while IFS= read -r line
do
var=$(tac -s " " <<< "$line" )
echo $var
done < input.txt
Run Code Online (Sandbox Code Playgroud)
这是具有任意输入行的 3 种方法
$ cat input.txt
Hello Earth end of line
Hello Mars another end of line
abra cadabra magic
$ ./reverse_words.sh
line of end Earth Hello
line of end another Mars Hello
magic cadabra abra
$ python -c "import sys;print '\n'.join([ ' '.join(line.split()[::-1]) for line in sys.stdin ])" < input.txt
line of end Earth Hello
line of end another Mars Hello
magic cadabra abra
$ awk '{for(i=NF;i>=1;i--) printf "%s ", $i;print ""}' input.txt
line of end Earth Hello
line of end another Mars Hello
magic cadabra abra
Run Code Online (Sandbox Code Playgroud)
与 python 相同的想法 - 我们将每一行分成单词数组,反转数组,然后打印出来。
$ perl -lane '@r=reverse(@F); print "@r"' input.txt
line of end Earth Hello
line of end another Mars Hello
magic cadabra abra
$ ruby -ne 'puts $_.chomp.split().reverse.join(" ")' < input.txt
line of end Earth Hello
line of end another Mars Hello
magic cadabra abra
Run Code Online (Sandbox Code Playgroud)
只需交换周围的话,与awk
:
awk '{print $2, $1}'
Run Code Online (Sandbox Code Playgroud)
例子:
% cat bar.txt
Hello Earth
Hello Mars
% awk '{print $2, $1}' bar.txt
Earth Hello
Mars Hello
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
23387 次 |
最近记录: |