12

我需要从 Unix 的文本文件中获取记录。分隔符是多个空格。例如:

2U2133   1239  
1290fsdsf   3234

从中,我需要提取

1239  
3234

所有记录的分隔符始终为 3 个空格。

我需要在 unix 脚本(.scr)中执行此操作并将输出写入另一个文件或将其用作 do-while 循环的输入。我尝试了以下方法:

while read readline  
do  
        read_int=`echo "$readline"`  
        cnt_exc=`grep "$read_int" ${Directory path}/file1.txt| wc -l`  
if [ $cnt_exc -gt 0 ]  
then  
  int_1=0  
else  
  int_2=0  
fi  
done < awk -F'  ' '{ print $2 }' ${Directoty path}/test_file.txt  

test_file.txt 是输入文件,file1.txt 是查找文件。但是上述方法不起作用,并且在 awk -F 附近出现语法错误

我尝试将输出写入文件。以下在命令行中工作:

more test_file.txt | awk -F'   ' '{ print $2 }' > output.txt

这正在工作并将记录写入命令行中的 output.txt。但是相同的命令在 unix 脚本中不起作用(它是一个 .scr 文件)

请让我知道我哪里出了问题以及如何解决这个问题。

谢谢,
维沙赫

4

8 回答 8

27

用一个分隔符替换多个分隔符的工作留给tr

cat <file_name> | tr -s ' ' | cut -d ' ' -f 2

tr翻译或删除字符,非常适合准备您的数据以cut使其正常工作。

手册指出:

-s, --squeeze-repeats
          replace each sequence  of  a  repeated  character  that  is
          listed  in the last specified SET, with a single occurrence
          of that character
于 2013-06-10T09:07:58.733 回答
12

这取决于cut您机器上的版本或实现。某些版本支持一个选项,通常是-i,这意味着“忽略空白字段”,或者等效地,允许字段之间有多个分隔符。如果支持,请使用:

cut -i -d' ' -f 2 data.file

如果不是(而且它不是通用的——甚至可能没有普及,因为 GNU 和 MacOS X 都没有这个选项),那么使用awk会更好,更便携。

但是,您需要将输出通过管道传输awk到循环中:

awk -F' ' '{print $2}' ${Directory_path}/test_file.txt |
while read readline  
do  
    read_int=`echo "$readline"`  
    cnt_exc=`grep "$read_int" ${Directory_path}/file1.txt| wc -l`  
    if [ $cnt_exc -gt 0 ]  
    then int_1=0  
    else int_2=0
    fi  
done

唯一的遗留问题是while循环是否在子 shell 中,因此不修改主 shell 脚本变量,只是修改这些变量的自己的副本。

使用 bash,您可以使用进程替换

while read readline  
do  
    read_int=`echo "$readline"`  
    cnt_exc=`grep "$read_int" ${Directory_path}/file1.txt| wc -l`  
    if [ $cnt_exc -gt 0 ]  
    then int_1=0  
    else int_2=0
    fi  
done < <(awk -F' ' '{print $2}' ${Directory_path}/test_file.txt)

这会将while循环留在当前 shell 中,但会安排命令的输出看起来好像来自文件。

空白${Directory path}通常是不合法的——除非它是我错过的另一个 Bash 功能;你在一个地方也有一个错字(Directoty)。

于 2010-12-06T15:14:10.480 回答
3

除了做同样事情的其他方法之外,您的程序中的错误是:您不能从 ( <) 重定向另一个程序的输出。转动你的脚本并使用这样的管道:

awk -F'   ' '{ print $2 }' ${Directory path}/test_file.txt | while read readline

等等

此外,使用“readline”作为变量名可能会也可能不会让您遇到问题。

于 2010-12-06T15:09:50.973 回答
2

在这种特殊情况下,您可以使用以下行

sed 's/   /\t/g' <file_name> | cut -f 2

得到你的第二列。

于 2012-01-18T22:18:36.767 回答
1

在 bash 中,您可以从以下内容开始:

for n in `${Directoty path}/test_file.txt | cut -d " " -f 4`
{
    grep -c $n ${Directory path}/file*.txt
}
于 2010-12-06T14:44:26.857 回答
1

这应该是一个评论,但由于我还不能评论,我在这里添加这个。这是来自这里的一个很好的答案:https ://stackoverflow.com/a/4483833/3138875

tr -s ' ' <text.txt | cut -d ' ' -f4

tr -s '<character>'将多个重复的实例压缩<character>为一个。

于 2019-03-26T19:07:20.900 回答
0

由于“Directo* t *y 路径”(脚本的最后一行)中的拼写错误,它在脚本中不起作用。

于 2010-12-06T14:59:33.530 回答
0

剪切不够灵活。我通常为此使用 Perl:

cat file.txt | perl -F'   ' -e 'print $F[1]."\n"'

您可以放置​​任何 Perl 正则表达式,而不是-F后的三倍空格。您以$F[n]的形式访问字段,其中n是字段编号(从零开始计数)。这样就不需要sedtr

于 2016-02-22T19:55:00.607 回答