用于读取文件和用|替换新文件的shell脚本符号

时间:2017-02-24 22:46:24

标签: bash shell awk sed solaris

我有如下文件的txt文件。

abc
def
ghi

123
456
789

预期产出

abc|def|ghi
123|456|789

我想用管道符号(|)替换新行。我想在egrep.After空行后使用它应该开始其他新行。

4 个答案:

答案 0 :(得分:6)

您可以尝试使用awk

awk -v RS= -v OFS="|" '{$1=$1}1' file

你明白了,

abc|def|ghi
123|456|789

<强>解释

RS设置为空/空值以使awk对空行序列进行操作。

来自POSIX specification for awk

  

<强> RS

     

RS的字符串值的第一个字符应为输入记录分隔符;一个默认情况下。如果RS包含多个字符,则结果未指定。 如果RS为空,则记录由包含一个或多个空行的序列分隔,前导或尾随空白行不应在输入的开头或结尾处产生空记录,并且a应始终为字段分隔符,无论FS的值是什么。

$1==$1使用OFS重新格式化输出作为分隔符,1true以便始终打印。

答案 1 :(得分:2)

这是使用GNU sed

的人
cat file | sed ':a; N; $!ba; s/\n/|/g; s/||/\n/g'

如果您正在使用BSD sed(Mac OS X打包的风格),则需要单独传递每个表达式,并使用文字换行符而不是\n({ {3}}):

cat file | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/|/g' -e 's/||/\
/g'

如果file是:

abc
def
ghi

123
456
789

你得到:

abc|def|ghi
123|456|789

这会将每个换行符替换为|(归功于more info),然后使用换行符替换||(即原始输入中的一对换行符)。

这里需要注意的是|不能出现在输入行的开头或结尾;否则,第二个sed会在错误的位置添加换行符。要解决此问题,您可以使用另一个不会在输入中作为中间值的字符,然后将该字符的单例替换为|并与\n配对。

修改

这是一个实现上述解决方法的示例,使用NUL字符\x00(应该很可能不会出现在您的输入中)作为中间字符:

cat file | sed ':a;N;$!ba; s/\n/\x00/g; s/\x00\x00/\n/g; s/\x00/|/g'

说明:

  • :a;N;$!ba;将整个文件放在模式空间中,包括换行符
  • s/\n/\x00/g;用NUL字符替换所有换行符
  • s/\x00\x00/\n/g;用换行符替换所有NUL对
  • s/\x00/|/g|
  • 替换NUL的剩余单身人士

BSD版本:

sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\x00/g' -e 's/\x00\x00/\
/g' -e 's/\x00/|/g'

编辑2

对于更直接的方法(仅限GNU sed),由@ClaudiuGeorgiu提供:

sed -z 's/\([^\n]\)\n\([^\n]\)/\1|\2/g; s/\n\n/\n/g'

说明:

  • -z使用NUL字符作为行尾(因此新行不会得到特殊处理,并且可以在正则表达式中匹配)
  • s/\([^\n]\)\n\([^\n]\)/\1|\2/g;<non-newline><newline><non-newline>的每个3个字符的序列替换为<non-newline>|<non-newline>
  • s/\n\n/\n/g用一个换行符替换所有换行符

答案 2 :(得分:1)

在原生bash中:

#!/usr/bin/env bash
curr=
while IFS= read -r line; do
  if [[ $line ]]; then
    curr+="|$line"
  else
    printf '%s\n' "${curr#|}"
    curr=
  fi
done
[[ $curr ]] && printf '%s\n' "${curr#|}"

测试:

$ f() { local curr= line; while IFS= read -r line; do if [[ $line ]]; then curr+="|$line"; else printf '%s\n' "${curr#|}"; curr=; fi; done; [[ $curr ]] && printf '%s\n' "${curr#|}"; }
$ f < <(printf '%s\n' 'abc' 'def' 'ghi' '' 123 456 789)
abc|def|ghi
123|456|789

答案 3 :(得分:1)

使用rs。例如:

rs -C'|' 2 3 < file

rs =重塑数据数组。在这里,我指定我想要2行,3列,并且输出分隔符是管道。