“读取”命令剥离'\ n'字符串

时间:2012-08-21 04:21:37

标签: bash

我想从一个看起来像这样的文件中提取数据:

BK20120802130531:/home/michael/Scripts/usb_backup.sh
BK20120802130531:/home/michael/Scripts/yad_0.17.1.1-1_i386.deb
BK20120802130731:/home/michael/Scripts/gbk.sh
BK20120802130131:/home/michael/Scripts/alt-notify-send.sh
BK20120802130131:/home/michael/Scripts/bk.bak
BK20120802130131:/home/michael/Scripts/bk.sh
BK20120802130131:/home/michael/Scripts/demande_password.sh

想法是在屏幕上显示(不创建临时文件,也不修改原始文件)以下内容:

alt-notify-send.sh
/home/michael/Scripts
bk.bak
/home/michael/Scripts
bk.sh
/home/michael/Scripts
demande_password.sh
/home/michael/Scripts
gbk.sh
/home/michael/Scripts
usb_backup.sh
/home/michael/Scripts
yad_0.17.1.1-1_i386.deb
/home/michael/Scripts

总结一下:

  1. 在':'
  2. 之前删除字符
  3. 将文件名放在相应的目录
  4. 之前
  5. 按字母顺序对文件名排序
  6. 在每个文件名及其相应目录之间进行回车
  7. 我成功完成了所有这些,但我的代码中仍有一个关于第4点的丑陋的事情:

    cut -f 2 -d ':' $big_file | \
    sort -u | \
    while read file ; do
       echo "$(basename "$file")zipzapzupzop$(dirname "$file")" # <-- ugly thing #1
    done | \
    sort -dfb | \
    while read line ; do
       echo $line
    done | \
    sed 's/zipzapzupzop/\n/' # <-- ugly thing #2
    

    一开始,我写过:

    echo "$(basename "$file")\n$(dirname "$file")"
    

    代替丑陋的东西#1,以便能够做到

    echo -e "$line"
    

    在第二次同时发牢骚。但是,read命令每次都会删除'\ n'字符串,以便我获取

    alt-notify-send.shn/home/michael/Scripts
    bk.bakn/home/michael/Scripts
    bk.shn/home/michael/Scripts
    demande_password.shn/home/michael/Scripts
    gbk.shn/home/michael/Scripts
    usb_backup.shn/home/michael/Scripts
    yad_0.17.1.1-1_i386.debn/home/michael/Scripts
    

    我试图用另一个'\'保护'\'字符,但结果是一样的。

    man read
    

    也无济于事。那么,这是一种正确的方法吗?

4 个答案:

答案 0 :(得分:1)

read是内置的shell,man read可能会为您提供(通常不相关的)系统调用的文档。

read -r会阻止read处理\序列。

完整的事情可以用一个awk脚本完成:

awk '
    {
        start = index($0, ":") + 1
        end = match($0, "[^/]*$")
        out[NR] = substr($0, end) "\n" substr($0, start, end - start - 1)
    }
    END {
        asort(out)
        for (i = 1; i <= NR; i++)
            print out[i]
    }'

答案 1 :(得分:0)

您可以使用以下管道执行此操作(应该在一行上,我已将其拆分并添加注释以提高可读性):

| sed -e 's/^[^:]*://'             # Remove from start of line to first ':'
      -e 's?/\([^/]*$\)? \1?'      # Replace final '/' with a space
| sort -k2                         # Sort on column 2 (filename)
| awk '{print $2"\n"$1}'           # Reverse fields

请参阅以下成绩单:

echo 'BK20120802130531:/home/michael/Scripts/usb_backup.sh
BK20120802130531:/home/michael/Scripts/yad_0.17.1.1-1_i386.deb
BK20120802130731:/home/michael/Scripts/gbk.sh
BK20120802130131:/home/michael/Scripts/alt-notify-send.sh
BK20120802130131:/home/michael/Scripts/bk.bak
BK20120802130131:/home/michael/Scripts/bk.sh
BK20120802130131:/home/michael/Scripts/demande_password.sh'
    | sed -e 's/^[^:]*://'
          -e 's?/\([^/]*$\)? \1?'
    | sort -k2
    | awk '{print $2"\n"$1}'

alt-notify-send.sh
/home/michael/Scripts
bk.bak
/home/michael/Scripts
bk.sh
/home/michael/Scripts
demande_password.sh
/home/michael/Scripts
gbk.sh
/home/michael/Scripts
usb_backup.sh
/home/michael/Scripts
yad_0.17.1.1-1_i386.deb
/home/michael/Scripts

请记住,对于包含空格的行,排序可能无法正常工作。

答案 2 :(得分:0)

如果您不需要处理文件名中的空格,则可以执行以下操作:

cat $bigfile | sed 's/.*://' | while read file; do
  echo "$(basename $file) $(dirname $file)"
done | sort | awk '{print $1"\n"$2}'

答案 3 :(得分:0)

假设您的文件名中没有哈希标记,则可以使用此coreutils管道:

cut -d: -f2- infile               \
| sed -r 's,(.*)/([^/]*)$,\2#\1,' \
| sort -t'#'                      \
| tr '#' '\n'
  • cut删除了第一部分。
  • sed拆分路径,交换文件名和目录,并用#分隔。
  • sort哈希标记分隔文本。
  • tr最后用换行符替换哈希标记。

如果您知道路径元素的数量,则可以使用更简单的版本:

cut -d: -f2- infile \
| sort -t/ -k4,4    \
| sed 's,(.*)/([^/]*)$,\2\n\1,'