![提取特定行并将其放在第一行 bash](https://linux22.com/image/212548/%E6%8F%90%E5%8F%96%E7%89%B9%E5%AE%9A%E8%A1%8C%E5%B9%B6%E5%B0%86%E5%85%B6%E6%94%BE%E5%9C%A8%E7%AC%AC%E4%B8%80%E8%A1%8C%20bash.png)
如果一行包含特定字符(例如“|”),如何提取该行并把它放在第一行?
例如:
varl="This is the first row (I might be specific)
...
This is the ith row (I might be specific)
...
this row contains I|am|sepcific|
...
This is the last row (I might be specific)
"
输出应如下所示:
varl="this row contains I|am|sepcific|
This is the first row (I might be specific)
...
This is the ith row (I might be specific)
...
...
This is the last row (I might be specific)
"
特定行可以出现在任何行中。
我做的有点混乱并且没有得到正确的结果:
new_varl=`echo "$varl" | grep '|'`\n`echo "$varl" | grep -v '|' `
但结果是:
new_varl="this row contains I|am|sepcific|\nThis is the first row (I might be specific)
...
This is the ith row (I might be specific)
...
...
This is the last row (I might be specific)"
\n
不能用作回车符
答案1
\n
不是回车符,而是换行符。回车符是\r
,换行符是 或\n
或\r\n
,\n\r
具体取决于您的平台。在 Unix 上是\n
.
您无法在由换行符分隔的文本中查找换行符。 grep 一次将正则表达式应用于 1 行,根据定义,一行通过换行符与其他行分隔,因此不能包含换行符。
使用任何 awk:
awk '/\|/{ print; next } { tail=tail $0 ORS } END{ printf "%s", tail }'
例如:
$ echo "$varl"
This is the first row (I might be specific)
...
This is the ith row (I might be specific)
...
this row contains I|am|sepcific|
...
This is the last row (I might be specific)
$ varl=$( echo "$varl" | awk '/\|/{ print; next } { tail=tail $0 ORS } END{ printf "%s", tail }' )
$ echo "$varl"
this row contains I|am|sepcific|
This is the first row (I might be specific)
...
This is the ith row (I might be specific)
...
...
This is the last row (I might be specific)
答案2
您的命令的问题除了过于复杂(长管道和嵌套反引号)之外,还在于它尝试用作n
命令,并且echo
在某些情况下使用它可能会修改其输出的数据。
这会将 in 中的值替换varl
为包含的所有行,|
后跟所有不包含的行|
:
varl=$( grep -F '|' <<<"$varl"
grep -v -F '|' <<<"$varl" )
或者
varl=$( grep -F '|' <<<"$varl"; grep -v -F '|' <<<"$varl" )
- 该
-F
选项强制grep
将模式表达式视为字符串(而不是正则表达式)。 - 这个东西是一些其他 shell
<<<"..."
的非标准功能,称为“here-string”。bash
它将给定的字符串提供给命令的标准输入流上的命令。作为标准替代方案,您应该通过管道传输来自 的输入printf '%s\n' "$varl"
,但不应该echo "$varl"
(请参阅为什么 printf 比 echo 更好?)。 - 应无条件按顺序运行的两个命令可以用文字换行符或 分隔
;
。
再次查看您尝试的命令(顺便说一句,它无法产生您显示的输出),我突然意识到您可能尝试用作\n
两个echo
+grep
管道之间的分隔符。如上所示,使用;
替代或文字换行符。
答案3
new_varl=`echo "$varl" | grep '|'`$'\n'`echo "$varl" | grep -v '|' `
答案4
将其放在引号中。
new_varl=`echo "$varl" | grep '|'`"\n"`echo "$varl" | grep -v '|' `
echo "$new_varl"
对于这样的任务,最好使用中间变量:
var_s=`echo "$varl" | grep '|'`
var_ns=`echo "$varl" | grep -v "$var_s"`
new_varl="$var_s\n$var_ns"
更易于阅读和维护。当然,这是一个品味问题,但是单行代码中的特定错误变得很容易注意到和解决。