0

我想从如下所示的文件中提取数据:

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. 在每个文件名与其对应的目录之间执行回车

我成功地做到了这一切,但我的代码中关于第 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"

在第二个圆球。但是,每次读取命令都会剥离 '\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

4 回答 4

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]
    }'
于 2012-08-21T04:55:15.527 回答
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

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

于 2012-08-21T04:30:01.800 回答
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,'
于 2012-08-21T07:33:47.367 回答
0

如果您不需要处理文件名中的空格,您可以这样做:

cat $bigfile | sed 's/.*://' | while read file; do
  echo "$(basename $file) $(dirname $file)"
done | sort | awk '{print $1"\n"$2}'
于 2012-08-21T04:38:09.020 回答