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"

2番目のWhileブークレ。ただし、読み取りコマンドは「\ 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シェル組み込みでありman read、(ほとんど無関係な) syscall のドキュメントを提供している可能性があります。

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

次のパイプラインでそれを行うことができます(1行である必要があります、私はそれを分割し、読みやすくするためにコメントを追加しました):

| 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 に答える