这是我第一次在这里发帖,所以请耐心等待。
我收到了bash作业,但我的教授完全没有帮助,他的笔记也是如此。
我们的任务是过滤和打印文件中的回文。在这种情况下,目录是:
/usr/share/dict/words
单词长度范围从3到45,并且应该只过滤小写字母(给出的字典包含字符和大写字母,以及小写字母)。即“-dkas-das”,所以像“q-evvavve-q”这样的东西可能算作回文,但我不应该把它当作一个合适的结果。
无论如何,我可以让它过滤掉x个单词并返回(但不过滤掉只有小写)。
grep "^...$" /usr/share/dict/words |
grep "\(.\).\1"
我可以使用后续行代表5个字母和7个等等:
grep "^.....$" /usr/share/dict/words |
grep "\(.\)\(.\).\2\1"
但教授不希望如此。我们应该使用循环。我得到了这个概念,但我不知道语法,就像我说的那样,笔记非常无益。
我尝试的是设置变量x = ...和y = ..并且在while循环中,x = $ x $ y但是这不起作用(语法错误)并且x + = .. < / p>
感谢任何帮助。甚至把我的非小写字母过滤掉了。
谢谢!
如果您要为解决方案提供解决方案或提示,则最好采用最简单的方法。 最好使用2个grep语句和一个循环。
再次感谢。
答案 0 :(得分:2)
像这样:
for word in `grep -E '^[a-z]{3,45}$' /usr/share/dict/words`;
do [ $word == `echo $word | rev` ] && echo $word;
done;
使用我的字典输出:
aha
bib
bob
boob
...
wow
<强>更新强>
正如评论中所指出的,将大部分字典读入for循环中的变量可能不是最有效的,并且可能会在某些shell中触发错误。这是一个更新版本:
grep -E '^[a-z]{3,45}$' /usr/share/dict/words | while read -r word;
do [ $word == `echo $word | rev` ] && echo $word;
done;
答案 1 :(得分:2)
多个grep
是浪费的。你可以简单地做
grep -E '^([a-z])[a-z]\1$' /usr/share/dict/words
一举,同样地,将表达式放在grep
的标准输入上,如下所示:
echo '^([a-z])[a-z]\1$
^([a-z])([a-z])\2\1$
^([a-z])([a-z])[a-z]\2\1$' | grep -E -f - /usr/share/dict/words
但是,常规grep
不允许超出\9
的反向引用。使用grep -P
,您也可以使用两位数的反向引用。
以下脚本在循环中构造整个表达式。不幸的是,grep -P
不允许使用-f
选项,因此我们构建了一个大的thumpin'变量来保存模式。然后我们实际上也可以简化为^(.)(?:.|(.)(?:.|(.)....\3)?\2?\1$
形式的单一模式,除了我们使用[a-z]
代替.
来限制为小写。
head=''
tail=''
for i in $(seq 1 22); do
head="$head([a-z])(?:[a-z]|"
tail="\\$i${tail:+)?}$tail"
done
grep -P "^${head%|})?$tail$" /usr/share/dict/words
单个grep
应该比在大输入文件上单独调用grep
22或43次快得多。如果要按长度排序,只需将其添加为管道末尾的过滤器;它应该比整个字典上的多次传递更快。
表达式${tail+:)?}
仅在tail
非空时评估为右括号和问号,这是强制\1
反向引用为非的方便方法可选的。有点类似,${head%|}
从$head
的最终值修剪最终的交替运算符。
答案 2 :(得分:2)
为什么要使用grep
? Bash很高兴为你做到这一点:
#!/bin/bash
is_pal() {
local w=$1
while (( ${#w} > 1 )); do
[[ ${w:0:1} = ${w: -1} ]] || return 1
w=${w:1:-1}
done
}
while read word; do
is_pal "$word" && echo "$word"
done
将其另存为banana
,chmod +x banana
并享受:
./banana < /usr/share/dict/words
如果您只想保留至少包含三个字符的字词:
grep ... /usr/share/dict/words | ./banana
如果您只想保留仅包含小写且至少包含三个字母的单词:
grep '^[[:lower:]]\{3,\}$' /usr/share/dict/words | ./banana
答案 3 :(得分:0)
好的,这是让你入门的事情:
我建议您使用上面的计划,只需生成“。”的数量。使用for循环。
这个问题将解释如何从3到45进行for循环:
How do I iterate over a range of numbers defined by variables in Bash?
for i in {3..45};
do
* put your code above here *
done
现在你只需要弄清楚如何制作“i”点数“。”在你的第一个grep中,你就完成了。
另外,看看sed,它可以为你编写非小写的答案..
答案 4 :(得分:0)
另一个使用Perl兼容正则表达式(PCRE)和递归的解决方案,严重受this answer的启发:
grep -P '^(?:([a-z])(?=[a-z]*(\1(?(2)\2))$))++[a-z]?\2?$' /usr/share/dict/words