【问题标题】:I have a text file in below format, I want to print it into column using shell script我有一个以下格式的文本文件,我想使用 shell 脚本将它打印到列中
【发布时间】:2017-09-02 15:22:15
【问题描述】:
~1
ACCOUNT1
34765367
001
5637463648374
1
32476743
85468456875
003
~1
~2
ACCOUNT2
23587458745647
1
002343
2347938457
~2

....就这样

我想把它打印成下面格式的另一个文件:

ACCOUNT134765367001563746364837413247674385468456875003
ACCOUNT22358745874564710023432347938457

我在下面写了这样的东西,它可以完美地工作到 ~9,但是对于 ~10,它会将 10 记录也添加到 ~1 记录,在 ~1 记录的末尾。我想我需要更新我的正则表达式模式...请帮助

max_input=2
path1=/home
line_number_m=1
while [ ${line_number_m} -le ${max_input} ]
do
o_p=""
sed -n "/^${line_number_m},/^~{line_number_m}/p" ${path1}/temp_op.txt | sed 
"s/^${line_number_m}//" > ${path1}/tmp.txt
while read val
do
if [ -z ${val} ]
then
continue
else
o_p=`echo ${o_p}``echo ${val}`
fi
done< ${path1}/tmp.txt
echo ${o_p} >>${path1}/tmp_output.txt
line_number_m=`expr ${line_number_m} + 1`
done
rm ${path1}/tmp.txt
tail -n +2 ${path1}/tmp_output.txt > ${path1}/output.txt
rm ${path1}/tmp_output.txt
exit 0

~1 和~1 内的记录可以是任意随机数或字符,甚至是空格,如下所示: ~1 001 13324324343 常见的 6 487364754557465 --2空格 5874654657 ---3 空间 48567846574 4568746574657 --5个空格--- ~1

我希望我的输出如下所示: 00113324324343COMMON6487364754557465--5874654657---485678465744568746574657-----

【问题讨论】:

  • 请告诉我们what you have tried。我们这里的大多数人都很乐意帮助你提高你的手艺,但作为短期无偿编程人员不太乐意。在MCVE 中向我们展示您迄今为止的工作、您期望的结果以及您得到的结果,我们将帮助您解决问题。
  • 我已经尝试过上面的代码。它有两个问题。第一个是当我传递 1 到 10 条记录时,它会附加第 1 条和第 10 条记录,第二个是它不考虑空格条记录(如果有的话)。

标签: bash shell sed


【解决方案1】:

gawk 或 awk 对我来说比 sed 更容易。 awk 已经处理了记录,所以它特别擅长这样的任务。你只需要告诉它如何识别记录分隔符,以及你想对这些字段做什么。在这种情况下,在偶数记录上,我们删除所有空格,然后打印。

gawk -v RS='~[0-9]+' 'NR%2==0 {gsub(/[[:space:]]/,"");print}'

这个依赖的 gawk 特性是复杂的(正则表达式)RS 变量。在 BSD 或 macOS 中,您可能需要以下内容,在连接记录中的所有字段之前清空第一个字段:

awk -v RS='~' 'NR%2==0 {$1="";gsub(/[[:space:]]/,"");print}'

如果您真的想在 sed 中执行此操作,我想您可以使用类似以下内容的方法来捏造它:

sed -Ene $'H;${x;s/[[:space:]]//g;s/~[0-9]+A/\\\nA/g;s/~[0-9]*//g;p;}'

这会将整个文件放入保存空间,执行与 awk 脚本相同的空格减少,然后在清除字段分隔符的过程中重新添加换行符。

【讨论】:

    【解决方案2】:

    试试这个,希望可以帮助你作为一个起点:

    #!/bin/bash
    
    while IFS='' read -r line || [[ -n "$line" ]]; do
        if [[ $line == ACCOUNT* ]]
        then
            printf '\n%s' "$line"
        elif [[ $line != ~* ]]
        then
            printf '%s' "$line"
        fi
    done < "$1"
    

    将其保存到文件中并尝试:

    ./script.sh data.txt
    

    同时检查这个答案:https://stackoverflow.com/a/2172367/1135424

    # The == comparison operator behaves differently within a double-brackets
    # test than within single brackets.
    
    [[ $a == z* ]]   # True if $a starts with an "z" (wildcard matching).
    [[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
    

    【讨论】:

    • 请注意,如果您使用您指定的 shebang #!/bin/sh 运行脚本,那么 (1) 不能保证使用 bash,并且 (2) 即使它使用 bash,也会在 POSIX 兼容模式下运行,不包括 [[。哦,另外,如果输入数据包含可能被解释为格式的百分比字符,您的 printf 将失败。
    • 没问题。顺便说一句,解决其他问题的方法是printf '%s' "$line"
    • 别忘了quote your variables
    【解决方案3】:

    管道:

    $ sed '/^~/d' data | tr -d '\n' | sed -re 's/(.)A/\1\nA/g' -e 's/$/\n/'
    ACCOUNT134765367001563746364837413247674385468456875003
    ACCOUNT22358745874564710023432347938457
    
    • 第一个sed 删除所有以~ 开头的行。
    • tr 将所有内容连接到一行输出中。
    • 最后一个 sed 再次将输入分成单独的行,使用字符 AACCOUNT)作为分隔符,并在末尾添加换行符。

    最后一个sed 需要GNU sed 才能插入带有\n 的换行符。

    【讨论】:

    • 作为记录,如果您的 shell 支持格式扩展,您仍然可以在 sed 中插入换行符,使用类似:-e $'s/$/\\\n/'
    【解决方案4】:
    $ sed '/^~/d' data | awk -v RS='A' -v OFS='' '$1 && $1=RS $1'
    ACCOUNT134765367001563746364837413247674385468456875003
    ACCOUNT22358745874564710023432347938457
    

    这是我对这个问题的第二个解决方案。

    它以sed 开头,删除所有以~ 开头的行。

    awk 然后将剩余数据读取为由字符 A 分隔的记录,并在输出之前连接字段(不带分隔符)。

    这不依赖于 GNU 实用程序。

    【讨论】:

      【解决方案5】:

      这可能对你有用(GNU sed):

      sed -rn '/^~/{:a;N;/^(~[0-9]+)\n(.*)\n\1$/!ba;s//\2/g;s/\s//g;p}' file
      

      收集连续分隔符之间的行,即以~n 开头的行,其中 n 是整数。删除分隔符,删除空格并打印。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多