【Linux】【neko】自作の小規模ツール

Linux 環境にて高頻度で使用する自作の小規模ツール。

【Sed】一行野郎と複数行野郎
【AWK】一行野郎と複数行野郎

行頭から連続する半角スペース 4個を 2個に置き替える(縮める)
xxd 実行結果の右側にある文字列部分を1行にする
すべて標準出力に書き出す
ファイル名に時刻を付与して cp する
ファイル名に時刻を付与して mv する
末尾に .orig を付けて保存する
引数名+時刻情報としてディレクトリを作る
指定したパスに temp.YYYY.MM.DD.hh.mm.ss という形式でディレクトリを作る
ファイルの指定位置から指定サイズ分だけ 0 埋めする
バイナリデータを C 言語の配列に変換する
ftpサーバにログインして引数で渡したファイルを put する

 

indent_4_to_2.sh

  • 行頭から連続する半角スペース 4個を 2個に置き替える(縮める)。
  • 第一引数にファイルを指定してやる。
  • なお、ファイルの上書きはしないので、必要に応じて上書き処理を作ること。
#!/bin/sh
unexpand -t 4 --first-only $1 | expand -i -t 2 

 

xxd_text_part.sh

  • xxd 実行結果の右側にある文字列部分を1行にする
#!/bin/sh

test   -z "$1" && echo "Usage: `basename $0` [file]" && exit 2
test ! -f "$1" && echo "Error: $1 was not found"     && exit 2

xxd $1 |
awk ' BEGIN {
    i = 0
    buff[NR] = 0
}
{
    # パターンに一致しない場合は最終行と見なす
    if( match($0, /^[a-fA-F0-9]{8}:( [a-fA-F0-9]{4}){8}( ){2}(.+)/) ) {
        sub(/  /, "\t\t", $0)
        $0 = gensub( /(.+)\t\t(.+)/ , "\\2", 1, $0 )
#       buff[i++] = $0
        printf("%s", $0)
    }
    else if( match($0, /^[ \t]*$/) ) {
        # 空行であればファイルの終端に達したとみなす
        exit(0)
    }
    else {
        # 非空行、かつ、パターン不一致であれば最終行として END に進む
        exit(0)
    }
}
END {
    # 最終行は半角スペース2個を区切りと見なして第2フィールドを取り出す
    buff[i++] = gensub(/(.+)  (.+)/, "\\2", "G", $0)
    for( n = 0; n < i; n++ ) {
        print(buff[n])
    }
}'

 

2to1.rb

  • stderr を含めて stdout に吐き出す
#!/usr/bin/env ruby
# Usage: ./2to1.rb [command [args...]]
# エラー出力を標準出力に繋ぐプログラム
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/37344 から一部追加した

def quote_shell(unquoted)
    quoted = unquoted.dup
    # \ -> \\
    quoted.gsub! %r"\\" do '\\\\' end
    # " -> \"
    quoted.gsub! %r'"' do '\\"' end
    # ` -> \`
    quoted.gsub! %r'`' do '\\`' end
    # $ -> \$
    quoted.gsub! %r'\$' do '\\$' end
    # newline -> \newline
    quoted.gsub! %r'\n' do "\\\n" end
    # ' ' -> '\ '
    quoted.gsub! %r' ' do '\ ' end
    quoted
end

# コマンドラインを一つの文字列にする(配列の連結)
def copy_cmdline(*args)
    tmp = ""
    args.each {|i|
        tmp << quote_shell(i) + " "
    }
    return tmp
end

STDERR.reopen(STDOUT)
cmd = copy_cmdline(*ARGV)
system(cmd)

 

ftpput.rb

  • ftpサーバにログインして引数で渡したファイルを put する
  • 事前に ftpサーバ名、ログインするユーザ名とパスワードを記述しておく必要がある。
#!/usr/bin/env ruby
require 'net/ftp'
require 'logger'

def help()
    printf("Usage: %s [local file]...\n", $0)
end

# デバッグログレベル
$log = Logger.new(STDOUT)
#$log.level = Logger::FATAL
#$log.level = Logger::ERROR
#$log.level = Logger::WARN
#$log.level = Logger::INFO
$log.level = Logger::DEBUG

Server   = "example.ftpserver"
Username = "username"
Password = "password"
Rdir     = "/tmp"

#--------- program start ---------#
if ARGV.length() < 1
    help(); exit(1)
end

ftp = Net::FTP.new 
ftp.connect(Server)
ftp.login(Username, Password)
ftp.binary = true
ftp.chdir(Rdir)
(1..ARGV.length()).each do |i|
    $log.debug sprintf("[%d] %s\n", i, ARGV[i-1])
    ftp.put(ARGV[i-1])
end
ftp.quit

 

backup.sh

  • ファイル名に時刻を付与して cp する
#!/bin/sh
# Usage: ./backup.sh [files or directorys...]

now=`date "+%Y.%m.%d.%H.%M.%S"`
files="/tmp/tmp.rename.$$"

[ -f "$files" ] && echo "$files is already existance. exit..." && exit 2

trap "rm -f $files; exit 1" 1 2 15

\touch $files

while [ $# != 0 ]; do
    case $1 in
          -*) echo "Could not rename: $1"
              shift ;;
          */) echo $1 | sed 's/\/$//g' >> $files
              shift;;
           *) echo $1 >> $files
              shift ;;
    esac
done

for i in `cat $files`
do
    if [ -f $i ]; then    ## file
          \cp -pi $i ${i}.${now}
          echo "BACKUP: ${i}.${now}"
    elif [ -d $i ]; then  ## directory
          \cp -pri $i ${i}.${now}
          echo "BACKUP: ${i}.${now}"
    fi
done

\rm -f $files

 

rename.sh

  • ファイル名に時刻を付与して mv する
#!/bin/sh
# Usage: ./renamesh [files or directorys...]

now=`date "+%Y.%m.%d.%H.%M.%S"`
files="/tmp/tmp.rename.$$"

trap "\rm -f $files; exit 1" 1 2 15

if [ $# -eq 0 ] ; then
    echo "Syntax Error" && echo "Usage:: $0 \$@" && exit 4
fi

while [ $# != 0 ]; do
    case $1 in
         -*) echo "Could not rename: $1"
             shift ;;
          *) echo $1 >> $files
             shift ;;
    esac
done

for i in `cat $files| sed 's/\/$//g'`
do
    if [ -f ${i}.${now} ]; then     # ファイルが既に存在する場合
         \mv $i ${i}.${now}_$$
    elif [ -d ${i}.${now} ]; then   # ディレクトリが既に存在する場合
         \mv $i ${i}.${now}_$$
    elif [ -f $i ] || [ -d $i ]; then
         \mv $i ${i}.${now}
        echo "RENAME: ${i} ==> ${i}.${now}"
    else
        echo "Error!! Not Found: $i"
    fi
done

\rm -f $files

 

orig.sh

  • 末尾に .orig を付けて保存する
#!/bin/sh
# Usage: ./orig.sh [files or directorys...]

now=`date "+%Y.%m.%d.%H.%M.%S"`
files="/tmp/tmp.rename.$$"

[ -f "$files" ] && echo "$files is already existance. exit..." && exit 2

trap "rm -f $files; exit 1" 1 2 15

\touch $files

while [ $# != 0 ]; do
    case $1 in
          -*) echo "Could not rename: $1"
              shift ;;
          */) echo $1 | sed 's/\/$//g' >> $files
              shift;;
           *) echo $1 >> $files
              shift ;;
    esac
done

for i in `cat $files`
do
    if [ -f $i ] && [ ! -f $i.orig ]; then
          \cp -pi $i $i.orig
          echo "BACKUP: ${i}.orig"
    elif [ -f $i ]; then    ## file
          \cp -pi $i ${i}.${now}.orig
          echo "BACKUP: ${i}.${now}"
    elif [ -d $i ] && [ ! -d $i.orig ]; then  ## directory
          \cp -pri $i ${i}.orig
          echo "BACKUP: ${i}.orig"
    elif [ -d $i ]; then  ## directory
          \cp -pri $i ${i}.${now}.orig
          echo "BACKUP: ${i}.${now}.orig"
    fi
done

\rm -f $files

 

mda.sh

  • 引数名+時刻情報としてディレクトリを作る
#!/bin/sh
# Usage: ./mda.sh [new dir]
# 引数名+時刻情報としてディレクトリを作る
# ex) $0 hoge -> mkdir hoge.`date +"%Y.%m.%d.%H.%M.%S"`

case $# in
    1) 
        if [ $1 = '/' ] || [ $1 = '//' ] ; then
            echo "Cancel: $1 is root directory"
            exit 0
        fi

        now=`date +"%Y.%m.%d.%H.%M.%S"`
        newdir=`echo $1.$now | sed 's/\/\//\//g'`
        [ -d $newdir ] && echo "$1 is already existing" && exit 1
        mkdir $newdir 
        echo $newdir;;

    *)  echo "Syntax Error!!"
        echo "Usage: $0  [dir-name]" 
            exit 1 ;;
esac ;

 

mdt.sh

  • 指定したパスに temp.YYYY.MM.DD.hh.mm.ss という形式でディレクトリを作る
#!/bin/sh
# Usage 1: ./mdt.sh          #    ./temp.2010.12.34.56.54.32 というディレクトリを作成する
# Usage 2: ./mdt.sh  /tmp/   # /tmp/temp.2010.12.34.56.54.32 というディレクトリを作成する

case $# in
    0)  
        now=`date +"%Y.%m.%d.%H.%M.%S"`
        mkdir temp.$now
        echo temp.$now
        exit 0 ;;
    1) 
        [ -f $1 ] && echo "Error!! $1 is already existing and file" && exit 1

        if [ $1 = '/' ] || [ $1 = '//' ] ; then
            echo "Cancel: $1 is root directory"
            exit 0
        fi

        now=`date +"%Y.%m.%d.%H.%M.%S"`
        newdir=`echo $1/temp.$now | sed 's/\/\//\//g'`
        [ -d $newdir ] && echo "$1 is already existing" && exit 1
        mkdir $newdir
        echo $newdir ;;
    *)  
        echo "Syntax Error!!"
        echo "Usage: $0  [dir-path]" 
        exit 1 ;;
esac ;

 

do_ffill.sh

  • ファイルの指定位置から指定サイズ分だけ 0 埋めする
  • 単に以下のように dd を実行しているだけだが、dd の引数は複雑なのでスクリプト化しておく
    • dd if=/dev/zero of=ファイル bs=1 seek=オフセット count=0埋めするサイズ conv=notrunc
  • 0 埋めではなく F 埋めしたい場合は以下のように tr を使う (Web で検索すればすぐに見つかる手法)
    • tr "\000" "\377" < /dev/zero
#!/bin/bash
# Usage: ./do_ffill.sh  -s 32  -c 64  a.txt
# hoge.txt の 32バイト目から64バイト分を 0 埋めする

usage() {
echo "Usage: $0 -s [seek bytes] -c [count] [file]" 
}

while getopts s:c: OPTION
do
   case $OPTION in
       s) SEEK="$OPTARG"
          [ "$SEEK" -lt 0 ] && echo "$SEEK: seek size error" && exit 2 ;;
       c) COUNT="$OPTARG"
          [ "$COUNT" -lt 0 ] && echo "$COUNT: seek size error" && exit 2 ;;
      \?) echo "$USAGE" 1>&2
          echo XXX
          exit 1 ;;
       *) ;;
    esac
done

readonly IF="/dev/zero"
readonly CONV="notrunc"

test -z "$SEEK"   && echo "\$SEEK is NULL"  && usage && exit 2
test -z "$COUNT"  && echo "\$COUNT is NULL" && usage && exit 2

shift `expr $OPTIND - 1` # check argument

[ $# -lt 0 ] && echo "ERROR: not found $1" && exit 0
FILE=$1
( [ ! -z "$FILE" ] && [ ! -f "$FILE" ] ) && echo "$FILE: No such file" && exit 2

\dd if="$IF" of="$FILE" bs=1 seek="$SEEK" count="$COUNT" conv=$CONV

 

bin2array.sh

  • バイナリデータを C 言語の配列に変換する
  • BINARY HACS の #4 より引用
#!/bin/sh
# BINARY HACKS (オライリー社) の #4 より引用している。

Usage() {
    echo "Usage 1: ./bin2array.sh  [input-file]"
    echo "Usage 2: ./bin2array.sh  [input-file]  [objname]"
}

test   -z "$1" && Usage && exit 4
test ! -f "$1" && Usage && exit 4

objname=${2:-objname} # 第一引数がなければ "objname" という文字列を設定

od -A n -v -t x1 $1 | sed -e '1i\
const unsigned char '$objname'[] = {
s/\([0-9a-f][0-9a-f]\) */0x\1,/g
$s/,$//
$a\
};
'