#analyzer
役に立つシェルスクリプト群
Last-modified: 2015-11-08 (日) 22:11:16
(2011-6-14追記)最近はこちらのページにポッドキャスト・動画ダウンロード、携帯プレーヤー関係等のスクリプトを掲載しています。私にとってはiTunesの代わりです。 初出 2006-8-18
最終更新 2015-10-29
私自身が重宝している自作シェルスクリプトを紹介します。
一応「役に立つ」と謳っていますが、ニッチな機能なスクリプトばかりです。実態は「一部の人だけに役に立つスクリプト群」です。 全て自由に使って頂いて結構です。 個々のスクリプトを丸ごと掲載するスタイルの為、ページ全体で重複部分が多くならないように、意識的に書式にバラエティを持たせてあります。たとえば文字列の切り出しはcut,awkのsubstr,bashの機能等、様々な方法を適当に使用しています。 Ubuntuの場合、デフォルトではsh=dashなので"if ["を使っている個所は手直しが必要です。 $ cd /bin ; sudo ln -sf bash sh sh=bashに変更してしまって対応することが多いです。(2010-3-4追記)最近はやらないです。ただし今後作成するものについてはbash専用を除いてはPOSIX準拠を(出来れば)心がけたいと思っています。 ファイルのダウンロード用リンク(他のスクリプトは画面からコピペしてください)
少し並べ替えました。
(おまけ)下の応用で私が実際に使用しているものdircp.shと似すぎていてあまりに冗長なので、おまけとして、期間限定(のつもり)でページ
|
私はFirefoxのブックマークもIEのお気に入り(インターネットショートカットファイル)形式で管理しています。 この方式のメリットとして、(1)管理がし易い(エクスプローラが使える為)、(2)ブックマーク以外のファイル類も一緒に保存しておくことができる、の2点が挙げられます。 Firefoxのブックマーク形式のままですと、非常に大量なブックマークの管理は次第に困難になってくると思いますが、IEのお気に入り形式だと何千個あっても管理は十分可能ですし、grepも出来ます。そしてお気に入りフォルダには、txt、doc、ppt、pdf等、あらゆる形式のファイルを一緒に置いておけるので、自分専用の強力な情報保存庫として使用できます。ただし本ツールは拡張子urlのファイルだけを処理するので、作成されたブックマークファイルにはブックマーク以外の情報は載りません(もちろんFirefoxもブックマークファイルにブックマーク以外を載せることを許可していません)。他の種類のファイルはエクスプローラ等からアクセスすることになります。 RSS等で集めたURLの内、後でまた見たいと思ったURLをIEのお気に入り形式して保存しておくことにしています。そしてそれをこのツールで時系列(更新時間の降順)に並べてFirefoxで活用するのが私のやり方です。 FirefoxでIEのお気に入りを作成する方法としては、ロケーションバーの左のアイコンをドラッグアンドドロップする方法を通常は使っています。Windows上だとそれだけでいいのですが、Linux版のFirefoxだとurlファイルではなくdesktopファイルが作成されてしまうので簡単な変換をおこなう必要があります。Firefoxのbookmarks.htmlからまとめて変換する場合はこちらのツールを使用します。Firefox3以降でのbookmarks.htmlを使ったブックマーク管理に関してはこちらを参考にして下さい。 |
今はOS間でブックマークを同期する方法が様々用意されているので、こんなものは時代遅れかもしれません。
$ convert-favorites-to-bookmarks.html.sh "/Windows... .../Favorites" bookmarks.html
みたいな感じで使用します。引数をわかりやく表すと、
$ convert-favorites-to-bookmarks.html.sh [お気に入りフォルダ] [出力先ファイル名]
ということになります。
UNIX・Linux環境汎用だし、単体で使用できるので、cron登録しておいて誰かのお気に入りをLAN内のhttpdに常に反映しておく、みたいな用途に向いていると思います。
その誰かのマシンのレジストリの、
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\Favorites
の%USERPROFILE%\Favoritesには、sambaサーバのドライブ上に設けたお気に入りフォルダの場所を書き込んでおけばいいかと思います。
もしくは、WindowsとLinuxのデュアル(マルチ)ブートのマシンとかでも役立つと思います。
ダウンロード convert-favorites-to-bookmarks.html.sh
(2008-5-22)Firefoxで作成した拡張子がURL(大文字)のインターネットショートカットファイルにも対応しました。
#!/bin/bash count_hierar() { local count=0 local src=${1} local str= while [ "${src}" != "" ] do str=${src%%/*} src=${src#*/*} if [ "$str" == "${src}" ]; then echo ${count} return fi count=$((count+1)) done } mk_spaces() { local count=${1} local spaces="" for ((k=0;k<$count;k++)) do spaces=${spaces}" " done echo "${spaces}" } list_onedir() { local relative=${1} local addflg=false local dir= cd "${relative}" [ "${relative}" == "." ] && relative="" if [ ${#relative} -gt 0 ]; then addflg=true WD="${WD}/${relative}" fi [ "${WD}" != "." ] && echo "${WD}">>${TMPFILE} find . -maxdepth 1 ! -name "." -type d|sort|while read i do dir=${i#*/} list_onedir "${dir}" done ls -tr ./*.{url,URL} 2>/dev/null|while read i do fname=${i#*/} echo "${WD}/${fname}">>${TMPFILE} done cd .. $addflg && WD=${WD%*/*} } analize_structure() { local str=${befdirpath} local shallowcnt=0 for ((j=$befhierarcnt;j>$hierarcnt;j--)) do shallowcnt=$((shallowcnt+1)) str=${str%*/*} done if [ "${str}" != "${dirpath}" ]; then shallowcnt=$((shallowcnt+1)) fi echo ${shallowcnt} return } exitproc() { rm -f ${TMPFILE}; } trap ' exitproc exit 1 ' 2 15 [ $# -lt 2 ] && echo "$0 favorites-dir bookmarks-file" && exit 1 BASEDIR=${1} DESTFILE=${2} hierarcnt=0 dirpath="." spaces="" [ "$(echo "${DESTFILE}"|cut -b 1)" != "/" ] && DESTFILE=$(pwd)/${DESTFILE} cd "${BASEDIR}" 2>/dev/null if [ $? -ne 0 ]; then echo "Can't move to ${BASEDIR}";exit 1;fi BASEDIR=$(pwd) TMPFILE=$(mktemp) WD="." list_onedir "." cd "${BASEDIR}" cat>"${DESTFILE}"<<EOT <!DOCTYPE NETSCAPE-Bookmark-file-1> <!-- This is an automatically generated file. It will be read and overwritten. DO NOT EDIT! --> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> <TITLE>Bookmarks</TITLE> <H1>Bookmarks</H1> <DL><p> EOT while read i do modifytime=$(stat -c %y "${i}"|sed 's/\-/\//g'|cut -b1-19) adddate=$(date -d "${modifytime}" +%s) befhierarcnt=${hierarcnt} befdirpath=${dirpath} fname=${i##*/} [ -d "${i}" ] && i=${i}/ dirpath=${i%*/*} hierarcnt=$(count_hierar "${dirpath}X") if [ ${hierarcnt} -le ${befhierarcnt} -a "${dirpath}" != "${befdirpath}" ]; then shallowcnt=$(analize_structure) for ((j=$befhierarcnt;j>$(($befhierarcnt - $shallowcnt));j--)) do spaces=$(mk_spaces $j) echo "${spaces}</DL><p>">>"${DESTFILE}" done fi spaces=$(mk_spaces $hierarcnt) if [ -d "${i}" ]; then basename=${fname} cat>>"${DESTFILE}"<<EOT ${spaces}<DT><H3 ADD_DATE="${adddate}">${basename}</H3> ${spaces}<DL><p> EOT else basename=${fname%*\.url} basename=${basename%*\.URL} URL=$(grep "^URL"<"${i}"|cut -b 5-|sed 's/\n$//'|sed 's/\r$//') echo -n " ${spaces}<DT><A ">>"${DESTFILE}" echo -n "HREF=\"${URL}\" ADD_DATE=">>"${DESTFILE}" echo "\"${adddate}\">${basename}</A>">>"${DESTFILE}" fi done<${TMPFILE} echo "</DL><p>">>"${DESTFILE}" exitproc
本来は1行で記述するところをecho -nで3行に分割したのは、wikiwiki.jpの制限を回避する為です。
このスクリプトをGnome上のランチャーに登録しておくと、
変換されて作成されたURLファイル(インターネットショートカットファイル)は完全にWindows互換です。
Gnomeデスクトップ上のファイルのみを対象としています。
※:上の説明でのURLファイルのアイコンは私の環境独自にカストマイズしたものです。この変更は簡単です。たとえばLinux Mint 13 MATEの場合、~/.icons/hicolor/48x48/mimetypes/application-x-mswinurl.pngという名前で好きな画像(アイコン)ファイルを置くだけです。(2009-11-20現在)Ubuntu9.10(デフォルトアイコンテーマはHumanity)では、アイコンをカスタマイズしてもファイルブラウザ上には反映されるものの、デスクトップ上には反映されないというバグがあるようです。(2010-5-4現在)Ubuntu 10.04でも9.10と同じ状態です。
※:私が使っているランチャー(gnomeのカスタム・アプリケーションのランチャ)の中身はこんな感じです。(2009-11-20現在)Ubuntu9.10では、ロケーションバー左のアイコンをドラッグ&ドロップしてURLリンク(desktop)ファイルを作成する機能にバグがあるようです。(2010-2-6追記)2009年12月頃には修正されていたと思います。
[~/.gnome2/panel2.d/default/launchers/convert-desktop-to-favorites.sh.desktop]
#!/usr/bin/env xdg-open [Desktop Entry] Encoding=UTF-8 Version=1.0 Type=Application Terminal=false Icon[ja_JP]=/usr/share/icons/gnome/48x48/filesystems/gnome-fs-bookmark.png Name[ja_JP]=お気に入りに変換 Exec=/home/disklessfun/bin/convert-desktop-to-favorites.sh Name=お気に入りに変換 Icon=/usr/share/icons/gnome/48x48/filesystems/gnome-fs-bookmark.png
ダウンロード convert-desktop-to-favorites.sh
上のリンクからダウンロードして使用して下さい。一部wikiwiki.jpでは載せられない文字を含んでいる為、下をコピペして保存してもうまく動きません。
ファイル名変換の仕様は好きなように変更すればいいと思います。Windows上では使用できる文字が少ないのでそれに合わせる為の変換機能を持つ必要があります。なお、ダウンロードしたファイルをそのまま使用してもWindows版のFirefoxを用いた場合よりWindows互換性の高いURLファイルを生成します。
(2009-02-17)ファイル名変更の機能を6ケース(6行)追加しました。今までの仕様でもLinux上で使用する限りは問題なかったのですが、Windows上ではまだ問題がありました。Windows上での適応度の確認にはUnDupというソフトで読めるか否かで判定しています。
(2009-3-12追記)掲載の状態ではIEの仕様に合わせてあり、出力するURLファイルには「[Default]セクション」も出力します。しかしFirefoxのアドレスバーのアイコンをドラッグ&ドロップして作成したURLファイルには「[Default]セクション」はなく「[InternetShortcut]セクション」だけです。したがってWindows上でも主にFirefoxを使用している方は、スクリプト中の[Default]セクション」を出力する部分の2行をコメントアウトしてFirefoxの仕様に合わせた方が、重複もしくは差分チェックが有効に働く等の面から適切ではないかと思います。
#!/bin/bash EXT=desktop DESKTOP1=/home/${USER}/Desktop DESKTOP2=/home/${USER}/デスクトップ cd "${DESKTOP1}" 2>/dev/null||cd "${DESKTOP2}"||exit ls ./*.${EXT} 2>/dev/null|while read -r i;do grep -q "^Type=Link$" "${i}" && echo "${i}" \ |while read -r i do URLLINE=$(grep "^URL=" "${i}") modifytime=$(stat -c %y "${i}"|cut -b1-4,6-7,9-10,12-13,15-19|sed 's/:/./') fname=${i#*/} fname=${fname%*$EXT}URL fname=$(echo "${fname}"|sed -e 's/~/~/'g) fname=$(echo "${fname}"|sed -e 's/»/-/'g) fname=$(echo "${fname}"|sed -e 's/"/”/'g) fname=$(echo "${fname}"|sed -e 's/\\///'g) fname=$(echo "${fname}"|sed -e 's/?/?/'g) fname=$(echo "${fname}"|sed -e 's/</</'g) fname=$(echo "${fname}"|sed -e 's/>/>/'g) fname=$(echo "${fname}"|sed -e 's/:/:/'g) fname=$(echo "${fname}"|sed -e 's/;/;/'g) fname=$(echo "${fname}"|sed -e 's/|/|/'g) fname=$(echo "${fname}"|sed -e 's/,/,/'g) fname=$(echo "${fname}"|sed -e 's/*/-/'g) fname=$(echo "${fname}"|sed -e 's/\^/-/'g) fname=$(echo "${fname}"|sed -e 's/ / /'g) fname=$(echo "${fname}"|sed -e 's/―/―/'g) fname=$(echo "${fname}"|sed -e 's/-/-/'g) fname=$(echo "${fname}"|sed -e 's/ê/e/'g) fname=$(echo "${fname}"|sed -e 's/ó/o/'g) fname=$(echo "${fname}"|sed -e 's/@/@/'g) while [ "$(echo "${fname}"|cut -b1)" == "-" ] do fname=$(echo "${fname}"|sed -e 's/^-//') done grep "^${URLLINE}.$" "${fname}" 2>/dev/null if [ $? -ne 0 ]; then echo -e "[Default]\r">"${fname}" echo -e "BASE${URLLINE}\r">>"${fname}" echo -e "[InternetShortcut]\r">>"${fname}" echo -e "${URLLINE}\r">>"${fname}" touch -t ${modifytime} "${fname}" fi rm "${i}" done;done
この項だけはPerlスクリプトです。
FirefoxのブックマークはWindowsとLinuxで共用できます。
私自身は最近はこのツールを使う機会が激減しました。WindowsでもメインのブラウザとしてFirefoxを使用しているのですが、最近はLinuxでも標準でNTFSを読み書きできるようになったので、WindowsのFirefoxで使っているブックマークをLinux側からも読み書きすることでブックマークの共用を実現しているからです。その共用に使う"ブックマーク"の具体的なファイル名はFirefox3以降ではplaces.sqliteです。Firefox3移行後しばらくはbookmarks.htmlを使って共用を実現していましたが、無理があるので現在は素直にplaces.sqliteで共用をおこなっています。Windows側、Linux側双方にProfileディレクトリがありますが、Windows側のplaces.sqliteにLinux側からシンボリックリンクを張って共用しています。 ところでここで触れたように、私は新しく作成したbookmarks.htmlを頻繁にFirefoxにインポートします。Firefoxの既存ブックマークにマージするのではなく、ブックマークをそっくり入れ替えます。この作業が簡単におこなえるように、大したことではありませんが私のFirefoxは少しだけカストマイズしてあります。以下に説明します。 Firefox3は起動時にブックマークを(1)places.sqllite、(2)bookmarkbackupsの中のバックアップ、(3)bookmarks.htmlの順番に探します。 (3)のbookmarks.htmlを読み込ませたい時に(1)のplaces.sqliteだけを削除すれば済むように、普段から(2)のbookmarksbackupsの中にバックアップを出力しない設定にしてあります。 browser.bookmarks.max_backupsを0です。 また、これはあまり必要なわけではないのですが、Firefox終了時にbookmarks.htmlを出力するように browser.bookmarks.autoExportHTMLをtrueにしてあります。 |
シェルスクリプトbmc.shとPerlスクリプトbmc.plとのペアで使用します。
Firefoxやmozillaのブックマークを、階層構造を保ったまま、Windowsで用いられるurlファイル(インターネットショートカットファイル)に変換します。
私はブックマーク(アドレス)と関連するファイルを一緒に管理したいので、ブックマークは全て、アドレス1個毎にファイルがバラバラに作成されるurlファイル(Internet Explorerのお気に入り形式)に変換して管理しています。(この管理の仕方を補助するものがこれです。)
ブックマークを変換するソフトはWindows用のものはありますが、UNIX用の物はなかったと思うので、これはとても役に立っています。
ここ(本日のhoge(2003-11-07)
)から入手したPerlスクリプトを活用して簡単に作成しました。
(著作権を主張されていないので、私がその派生物をここで発表しても良さそうです。もちろん私もbmc.plに著作権を主張しません。)(2006-8-25:元にしたPerlスクリプトの作者様に基本的に自由に使用して良いとのお答えを頂きました。)
このPerlスクリプトの、bookmarks.htmlの階層構造を解釈する部分を参考にして作成したのがbmc.plです。自分自身ではbookmarks.html解析の努力を全く払っていません。
シェルスクリプト+Perlスクリプト(ZIP圧縮) 2008-5-23 更新
utf-8環境用となっています。
2006-9-5 firefox 1.5系でのシングルクォートの取扱仕様変更に対応しました。
(2007-7-9) urlファイルの更新時間をfirefox上でそのブックマークを追加した時間に一致させる機能を追加しました。これは以前からおまけで公開していた版とは異なります。
シェルスクリプトでファイルの更新時間を操作するサンプルとしては、これとかこれがあります。どちらもls --full-timeではなくstatを使っています。この項のものは、Perlを使っています。wavedash(~、いわゆる、にょろ)の処理もおこなっています。
(2008-5-23)上のconvert-favorites-to-bookmarks.html.shで作成した直後の「ADD_DATEと>が続いているファイル」を処理できませんでしたが、対応しました。
BookMarkConverter.zip (2008-11-22)ダウンロード(BookMarkConverter)停止
ダウンロード convert-bookmarks.html-to-favorites.pl
(2009-02-17)convert-desktop-to-favorites.plと同様の変更を加えました。
(2008-12-15)正しいファイルに差し替え。
(2008-11-22)単一Perlスクリプトに変更してダウンロード開始。
$ convert-bookmarks.html-to-favorites.pl firefox-setting-dir/bookmarks.html destination-dir
みたいな感じで使用します。destination-dir下に階層構造まで含めて変換されます。
従来のBookMarkconverter.zipに含まれていたbmc.plに7行追加しただけのものです。
ていうか、最初から単一のPerlスクリプト形式でも良かったんですが、シェルスクリプトのページに載せるために無理やり呼び出し用のシェルスクリプトを使用していたというのが実情です。
(2009-3-12追記)掲載の状態ではIEの仕様に合わせてあり、出力するURLファイルには「[Default]セクション」も出力します。しかしFirefoxのアドレスバーのアイコンをドラッグ&ドロップして作成したURLファイルには「[Default]セクション」はなく「[InternetShortcut]セクション」だけです。したがってWindows上でも主にFirefoxを使用している方は、スクリプト中の[Default]セクション」を出力する部分の2行をコメントアウトしてFirefoxの仕様に合わせた方が、重複もしくは差分チェックが有効に働く等の面から、適切ではないかと思います。
(2008-12-6)失礼しました。VLCとかxineは直接isoファイルを読み込む機能を持っていたんですね。ワンライナーで済む問題でした。
DVD視聴ソフトとしては使い方に慣れが必要ですが、好みでVLCを呼び出しています。VLCの設定でDeinterlaceをデフォルトにしておけば、ファイルブラウザ(Nautilus)上でisoファイルをダブルクリックするだけでDVDが次々と視聴できます。
[isoplay.sh]
exec vlc dvd:///"$1"
実際にはファイルブラウザ上でisoファイルの開き方として「vlc dvd:///%f」か「xine dvd:///%f」を登録すれば済みます。
locateコマンドに、grepコマンドのiオプション、findのinameオプションに相当する機能を追加します。
locateコマンドについては以下のリンクを参照して下さい。
例えば
$ locate-i "personal toolbar folder"
で、ファイル名の一部に次のどの文字列が含まれていても全て探し出すことができます。
Personal Toolbar Folder
PeRSOnaL toOLBaR fOLDeR
PERSONAL TOOLBAR FOLDER
(2010-3-22)dashでエラーが出力されないように修正しました。
#!/bin/sh [ $# -lt 1 ] && exit src=$1 lowstr=`echo "$src"|tr \'[A-Z]\' \'[a-z]\'` cnt=`echo "$lowstr"|awk 'BEGIN {FS="\n"};{print length($1)}'` while [ "$cnt" -gt 0 ] do low=`echo "$lowstr"|awk 'BEGIN {FS="\n"};{print substr($1,1,1)}'` lowstr=`echo "$lowstr"|awk 'BEGIN {FS="\n"};{print substr($1,2)}'` upp=`echo $low|tr \'[a-z]\' \'[A-Z]\'` if [ "$low" = "$upp" -o "$low" = " " ]; then str=$str$low else str=$str[$low$upp] fi cnt=`expr $cnt - 1` done locate "*$str*"
(2009-3-31追記)dpkg-query -Sがありました。あるんじゃないかなあ?と思いながらも自前で作成したのでした。以下の説明にあるように少し仕様が違います。
rpm系を経験してからdeb系に移るとdpkg -Sの出力は不便だと感じると思います。
試しにdpkg -S ftpやdpkg -S wを試みてみて下さい。出力が多すぎて何がなんだかわかりませんよね。
このスクリプトを使用するとこんな感じになります。
$ dpkg-qf /usr/bin/ftp ftp: /usr/bin/netkit-ftp
$ dpkg-qf /usr/bin/w procps: /usr/bin/w.procps
一目でどのパッケージに属しているか、そして実体ファイルが何なのかがわかるようになります。
このスクリプトは本家rpm -qf(およびdpkg-query -S)とは異なり、指定されたファイルがシンボリックファイルである場合には実ファイルまで辿る仕様となっています。なので、自分で独自に作成したシンボリックリンクを引数に指定した場合でもそのコマンドの実体ファイルがどのパッケージに属しているかを表示することができます。たとえば先ほどのwを例にとると、
$ ln -s ../../../usr/bin/w /home/disklessfun/bin/my-command $ dpkg-qf /home/disklessfun/bin/my-command procps: /usr/bin/w.procps
となります。
これを開発したりカストマイズする際なんかにはとても役立ちます。
[dpkg-qf]
#!/bin/bash -e test $# -lt 1 && echo "eg. $0 fullpath" && exit 1 seekfile() { local fpath=$1 local dirpath line sympath while test -L "${fpath}" do dirpath=${fpath%*/*}/ line="$(stat "${fpath}"|grep "File: ")" line="${line##*\`}" line="${line%*\'*}" if test "${line:0:1}" != "/"; then fpath="${dirpath}${line}" else fpath="${line}" dirpath=/ fi done echo "${fpath}" } test "${1:0:1}" != "/" && echo "$1 must be a full path" && exit 1 fullpath=${1} fullpath=$(seekfile "${fullpath}") filename=${fullpath##*/} dpkg -S "${filename}"|grep "${fullpath}$"
このスクリプトをデモってみます。
# mkdir /work # cd /work # dircp.sh ../var var
この操作で/var以下のディレクトリのみのコピーが/work/の中に作成されます。
既にコピーを作成した後に再度実行した場合は、コピー元とコピー先のディレクトリのプロパティを合わせる動作だけをおこないます。不要ファイルを削除した際にディレクトリのプロパティが変化することを避けたい場合に役立てると思います。
あまり需要はないと思いますが一応公開しておきます。Java開発者の方とかには役に立つかもしれません。
ソースをあまり読まない人用に補足説明をしておきます。
このスクリプトの働き自体は「(cd "$1";find . -type d|cpio -o)|(mkdir -p "$2";cd "$2";cpio -idm)」と同じです。(「find "$1" -type d|cpio -pdm "$2"」だと思う人もいると思いますが、少し違います。)
このスクリプトはもっと複雑なコピーや加工をおこなうスクリプトのベースとして掲載しています。(このスクリプトの起源は全く異なる用途でした。)サンプルとしては少し複雑すぎる実際の応用編がこれです。
(2007-7-8) 下側のループでmkdir -pすれば上側のループは必要ありません。しかし、それだと処理的に汚いと思うので上側のループを設けています。まあ、お好みの範囲です。上側のループの -pは再度実行した際にエラーを出さないことを意図しています。
#!/bin/sh set -e SRCEDIR=$1 DESTDIR=$2 BASEDIR=`pwd` mkdir -p "${DESTDIR}" || exit cd "${SRCEDIR}" || exit find . -type d|while read i do cd "${BASEDIR}" cd "${DESTDIR}" mkdir -p "${i}" done cd "${BASEDIR}" cd "${SRCEDIR}" find . -type d|sort -r|while read i do cd "${BASEDIR}" cd "${SRCEDIR}" DIRMODE=`stat -c %a "${i}"` DIRUSER=`stat -c %u "${i}"` DIRGROP=`stat -c %g "${i}"` DIRTIME=`stat -c %y "${i}"|cut -b1-4,6-7,9-10,12-13,15-19|sed 's/:/./'` cd "${BASEDIR}" cd "${DESTDIR}" chmod $DIRMODE "${i}" chown $DIRUSER "${i}" chgrp $DIRGROP "${i}" touch -t $DIRTIME "${i}" done
上と中身が殆ど同じで冗長になってしまうのですが、成り行き上掲載します。
Windowsのエクスプローラでフォルダをコピーまたは移動するとコピー先または移動先のフォルダの更新時間は元と異なった値になってしまいます。これが気にいらない人はrobocopyを使うらしいのですが、私はエクスプローラでコピーした後、下の内容のシェルスクリプトを使って"更新時間だけ"をコピーします。
ファイル名にntfsと付いていますが、実際にはFAT,FAT32でもext3でも使用できます。
[ntfsdirs-time-copy.sh]
#!/bin/sh if test $# -lt 2; then echo "eg. $0 Source-dir Destination-dir" exit fi SRCEDIR=$1 DESTDIR=$2 BASEDIR=`pwd` cd "${SRCEDIR}" || exit cd "${BASEDIR}" cd "${DESTDIR}" || exit find . -type d|sort -r|while read i do case $i in ./RECYCLER/*|./Recycled/*|./System\ Volume\ Information/*) ;; *) cd "${BASEDIR}" cd "${SRCEDIR}" DIRTIME=`stat -c %y "${i}"|cut -b1-4,6-7,9-10,12-13,15-19|sed 's/:/./'` cd "${BASEDIR}" cd "${DESTDIR}" echo "${i}" touch -c -t $DIRTIME "${i}" ;; esac done
レンタルした2層DVDを1層化して手元に残すというのはよくある手ですが、出来ることなら元の画質のままで残したいものです。かといって、いくら大容量ハードディスクが安くなったとはいえ、滅多に見る予定のないDVDを長期間ハードディスクに残しておきたくもありません。そこで私がよくやるのはDVDISOイメージをバイナリで2分割して2枚の片面DVD-(+)Rに焼くという手法です※。
※ここによると、この行為は現在の著作権法に違反していないそうです。(2012-6-21追記)2012年10月1日以降は違法となります。
(2009-9-15)小改造を加えまして、isoファイルだけでなく、あらゆる種類のファイル、あらゆる拡張子のファイルに標準対応しました。isoファイル以外でもスクリプトを修正せずにそのまま処理できます。
ヘッダ部のコメントにありますが、このスクリプトを動作させる為にはいくつかのコマンドをパスワードなしでsudoできるように/etc/sudoersの末尾に追記しておく必要があります。ヘッダ部にある設定は最小限の設定です。既にあらゆるコマンドをパスワードなしでsudoできるように設定済み等の場合は新たに設定する必要はありません。
このスクリプトは私が長らく手動でおこなってきた操作と全く同じ仕様にしています。
バッチファイルを同梱していますが、私自身がそれを使うことは今後もまずないと思います。Linux上で1枚目に入っている前半部をハードディスクにコピーし、2枚目に入っている後半部を前半部の後ろにcatした方が簡単だし速いからです。
最後のベリファイチェックはハードディスクに障害でもない限り、まず普通は必要ありません。なので途中で[Ctrl]+[C]してもいいようになっています。作業ディレクトリ(分割DVDのボリュームラベル名のディレクトリ)が削除されていれば分割ISOファイルの作成は既に終わっています。
いつものように説明代わりにset +xして経過を目に見えるようにしています。
スクリプト中で使用しているmkisofsですが、私は本物のmkisofsコマンドを使用しています。Winsows 2000でも読めるようにUDF1.5で作成する為です。最近のディストリビューションの標準では/usr/bin/mkisofsはmkisofsの後継的存在であるgenisoimageへのシンボリックリンクになっていますが私はそのシンボリックリンクを削除して手動でmkisofsをインストールしています。(2010-3-14追記)最近のgenisoimageは互換性の問題が解消したような気がします。
(2010-2-6追記)ここにも書きましたが、LinuxでのNTFSへの書き込み機能は安全ですが、不完全なものです。作業ディレクトリ(=カレントディレクトリ)がNTFSの場合、フラグメントが進んでいて且つ空き容量に余裕が少ない場合には処理が途中でストップする場合がありえます。このことは一応頭のどこかに留めておいて下さい。
(2010-2-10追記)losetupコマンドにfオプションがない、古い環境でも使えるように修正しました。あと、前半で[Ctrl]+[C]した場合にも作業ディレクトリを消すようにしました。←今までは処理内容をゆっくり観察できるようにわざと残してありましたが…
(2010-3-14追記)先月の更新内容にバグがありました。本日その修正版をアップしました(自分専用のmkisofsのチェック箇所も紛れ込んでいたので一緒に削除しました)。前回の版では完全に勘違いをしていて使ってはいけない箇所でtrを使用していました。本日、前回の更新以来始めて本スクリプトを使用して気づきました。前回のバグ入の版は10人程度の方がダウンロードされたようですが、バグの害について説明しておきます。このバグはいつも害を及ぼすとは限らず、mktempで作成したテンポラリーファイルに数字が含まれていた場合のみ出現します。で具体的な内容ですが、たとえば分割対象のisoファイルのボリュームラベルがTHIS_IS_ITなら仕様上は分割isoのボリュームラベルはTHIS_IS_IT_1とTHIS_IS_IT_2にならなければならない筈ですが、バグが現れた場合にはDVD_ISO_1とDVD_ISO_2になります。もちろん連結してisoを再作成すればそのボリュームラベルはちゃんとTHIS_IS_ITになりますから、気にするほどの害はなかったとも言えます。
(2015-1-5追記)新しい環境で使用したところ、引数なしでmountコマンドを実行した際の仕様が変更されていて、またDVD_ISO_1、…になってしまっていました。使用コマンド数を減らそうとlosetupの使用を控えたことがあだになりました。素直にlosetupコマンドを使用する仕様に変更して対応しました。
(2015-1-12追記)。losetup使用に従って丸々ソースファイル名で検索する必要が生じました。[]を含むファイル名に対応する為エスケイプ処理を加えました。また2x4.7GBサイズに対応する為allow-limited-size指定を追加しました(もう互換性の問題を心配する必要はほぼありません)。あと私の環境のgenisoimageのバグなのか?ボリュームラベル長が30バイト以上だとラベル末尾が文字化けするので29バイト以内に切り詰めるようにしました。
ダウンロード gen-splitted-isoimage.sh 2015-1-12更新
ソースファイル名が128文字を超えてないかのチェックにはこのスクリプトの64を128に変更したものを使って下さい。
(2015-10-29追記)最近はBDの方がDVDよりもはるかに容量当たりの単価が安いので本スクリプトの出番も少ないかもしれません。ただしもちろん本スクリプトは、BD一層に入りきらない巨大サイズのファイルを分割する用途にも使えます。
[gen-splitted-isoimage.sh]
#!/bin/bash -ex # Needed settings in /etc/sudoers. #disklessfun ALL=(ALL) NOPASSWD: /usr/bin/volname #disklessfun ALL=(ALL) NOPASSWD: /bin/mount #disklessfun ALL=(ALL) NOPASSWD: /bin/umount gen-autorun-inf() { local dirpath=${1} echo -e "[autorun]\r">"${dirpath}/autorun.inf" echo -e 'open=explorer.exe /n,\\'"\r">>"${dirpath}/autorun.inf" } escapepattn() { local pattn=${1} pattn="`echo "${pattn}"|sed -e 's/\[/\\\[/'g`" pattn="`echo "${pattn}"|sed -e 's/\]/\\\]/'g`" escapedmatchpattn=${pattn} } escapedmatchpattn= test $# -lt 1 && echo "eg. $0 hoge.iso[img,dmp,tgz, etc]" && exit 1 SRCFILE=$1 filename=${SRCFILE##*/} ext=${filename##*\.} test "${ext}" = "${filename}" && echo "Extension not found" && exit 1 basename=${filename%*\.$ext} dirname=${SRCFILE%*/*} test "${dirname}" = "${filename}" && dirname=. MNTDIR=$(mktemp -d) set +e sudo mount -o ro,loop "${SRCFILE}" ${MNTDIR} RET=$? set -e if [ $RET -eq 0 ]; then escapepattn "${SRCFILE}" LODEV=$(losetup -a|grep "${escapedmatchpattn}"|cut -d":" -f1|tail -1) #VOLNAME="$(sudo volname ${LODEV}|tr -cd '0-9A-Z_')" VOLNAME="$(sudo volname ${LODEV}|tr -d '\040')" sudo umount ${MNTDIR} else VOLNAME=SPLITTED fi rmdir ${MNTDIR} test -z "${VOLNAME}" && VOLNAME=DVD_VIDEO vollength=${#VOLNAME} #test ${vollength} -gt 30 && VOLNAME=${VOLNAME:0:30} test ${vollength} -gt 27 && VOLNAME=${VOLNAME:0:27} filesize=$(stat -c %s "${SRCFILE}") filesizeM=$(($filesize / 1048576)) halfsizeM=$(($filesizeM / 2)) exitproc1() { rm -rf "${VOLNAME}_1" "${VOLNAME}_2" } trap ' exitproc1 exit 1 ' 2 15 mkdir "${VOLNAME}_1" "${VOLNAME}_2" gen-autorun-inf "${VOLNAME}_1" gen-autorun-inf "${VOLNAME}_2" set +x basenames="$(echo "${basename}"|iconv -f UTF-8 -t CP932)" echo -n "COPY /B \"${basenames}.000\"+\"${basenames}.001\" \"${basenames}.$ext\ ""> \ "${VOLNAME}_2/${basename}.bat" set -x echo -e "\r">>"${VOLNAME}_2/${basename}.bat" WD=$(pwd) /bin/bash -ex -c "cd "${dirname}";md5sum \"${filename}\" > \ "${WD}/${VOLNAME}_2/md5sum.txt"" dd if="${SRCFILE}" bs=1M count=$halfsizeM of="${VOLNAME}_1/${basename}.000" #mkisofs -V "${VOLNAME}_1" -udf -r -o "${VOLNAME}_1.iso" "${VOLNAME}_1" genisoimage -V "${VOLNAME}_1" -allow-limited-size -r -o "${VOLNAME}_1.iso" "${V OLNAME}_1" rm -rf "${VOLNAME}_1" dd if="${SRCFILE}" bs=1M skip=$halfsizeM of="${VOLNAME}_2/${basename}.001" #mkisofs -V "${VOLNAME}_2" -udf -r -o "${VOLNAME}_2.iso" "${VOLNAME}_2" genisoimage -V "${VOLNAME}_2" -allow-limited-size -r -o "${VOLNAME}_2.iso" "${V OLNAME}_2" orghash="$(cat "${VOLNAME}_2/md5sum.txt")" rm -rf "${VOLNAME}_2" exitproc2() { sudo umount "${MNTDIR1}" sudo umount "${MNTDIR2}" rmdir ${MNTDIR1} ${MNTDIR2} } trap ' exitproc2 exit 1 ' 2 15 MNTDIR1=$(mktemp -d) MNTDIR2=$(mktemp -d) sudo mount -o loop,ro "${VOLNAME}_1.iso" "${MNTDIR1}" sudo mount -o loop,ro "${VOLNAME}_2.iso" "${MNTDIR2}" newhash="$(cat "${MNTDIR1}/${basename}.000" "${MNTDIR2}/${basename}.001"|md5sum )" set +x echo; echo "Original hash value." echo "${orghash}";echo echo "Archived hash value." echo "${newhash}";echo set -x exitproc2 set +x echo "Done."
私はよくLinux上でLinux・Windows兼用DVDを焼きます。Joliet形式の場合(最近はその必要性はあまりないと思います。関連記事)、ディレクトリ名、ファイル名の長さが64文字以内という制限があります。それを満たしているかのチェックに使います。まあ実際は他の目的用のスクリプトのベースになるかなってところでしょうか。
Windows用にこんなソフトがありますが、そのシェルスクリプト版といったところでしょうか。ただしこちらに修正機能はありません。
※:最近のmkisofsには -joliet-long というオプションがあって、それを使うとJolietでも103文字まで許されるそうです。規格外なのですが使えるそうです。
bash完全限定です。zshやkshはマルチバイト文字の扱いが異なり、間違った結果が出力されてしまいます。
#!/bin/bash find .|while read i do fname=${i##*/} length=${#fname} if [ ${length} -gt 64 ]; then echo "${i#*/*} :${length}" fi done
上のchkjoliet.bashと同じく、Linux・Windows兼用DVDを焼く前のチェックに使ったりします。
Linuxで作成したDVDの中身をWindows上で読み込んでハードディスクにコピーしている途中にフォルダ名やファイル名の重複エラーが発生してしまうことがあります。そんなことがないようにこのスクリプトでDVD作成前にチェックをおこないます。まあ余程まぎらわしいファイル名が多数ある場合以外は目視で事足りるわけですけど
#!/bin/sh exitshori() { rm -f /tmp/dupchk*; } trap ' exitshori exit 1 ' 2 15 tmpfile1=/tmp/dupchk.tmp find . ! -name ".">$tmpfile1 cat $tmpfile1|sort -f -u |while read i do hit=`grep -i "^$i$" $tmpfile1|wc -l` if [ $hit -ge 2 ]; then echo "hit $hit" echo "$i" fi done exitshori exit 0
本スクリプトはMicrosoft提供のツールとは違い、自動計算でブートセクタのバックアップを取り出すことができます。また、Windowsがブートしない状況でも、One CD Linux上で作業がおこなえます。
当初、ブートパーティションのみに使用可能と記していましたがデータ専用のパーティションでも使用できることがわかり、2008-2-1に修正しました。
当サイトでは以前からNTFSのPBRを完全に壊してしまった場合の私なりの修復法をこのページに載せているわけですが、このほど(2008-1-11)読者の方が当サイトの掲示板に「NTFSにはPBRのバックアップがパーティションの最後尾に保存されている」と書き込んで下さいました。このことを私も以前に見聞きしたような気がしますが、すっかり頭から消えていました。(Microsoftの資料) 早速、実際に確認作業をおこないました。バックアップのPBR(末尾のセクタ)を抽出するスクリプトを作成し、パーティションの末尾のセクタを先頭セクタ(PBR)に上書きコピーすることによっても、NTFSのPBRが修復出来ることをWindows XP,2000の環境で確認しました。
ダウンロード extract-backuped-pbr.sh (2015-7-8更新)最近のfileコマンドに対応しました。最新のLinux環境でも最後の説明メッセージが出るようになりました。 (2010-5-15更新)(簡単に言うと)Windows 7に対応しました。従来のものはハードディスクの標準的な使い方をそのままプログラミングしたようなものだったんですが、その方法ではWindows 7が作成する環境でfdiskコマンドがうまく対応できないので、別の(もっとシンプルな)方法を使う内部仕様に変更しました。
(2008-12-28更新)ダブルクォートが抜けていて、厳密に言うと文法が間違っていた個所を修正しました。多分動きに違いはないと思います。 (2008-12-16更新)スクリプト内部で使用しているGNU fileコマンドの最近の仕様変更に対応しました。Ubuntu8.10への対応です。
旧(厳密には旧旧)版もダウンロードできるようにしておきます。ダウンロード old.extract-backuped-pbr.sh
ただし、このスクリプトは当該パーティションがシリンダ境界に沿って確保されている場合のみ正常に動作します。まあ殆どの環境ではパーティションはシリンダ境界に沿って確保されているので、多分、一応は殆どの環境に適合していると思います。参考((2010-5-15追記)現在の版はシリンダ境界に依存しません。このページの補足)。
このスクリプトはLinux専用です。だからこそ、Windowsが起動しなくなった状態の復旧に向いているわけです。KNOPPIXやUbuntuライブCD上でも使用可能なので、わざわざLinuxをインストールする必要はありません。理想を言えば、ネットワーク上にこのようなものを仕込んだサーバを設置しておくと、障害復旧作業が非常に迅速におこなえると思います。
Linuxに詳しくない人のために簡単にTipsを書いておきます。まずrootユーザになるかsudoで fdisk -l を実行して下さい。Linuxでパーティションをどのように表記するかがわかります。もし、このときに当該パーティションについて「シリンダ境界に従っていない」等のメッセージが表示されれば、このスクリプトの実行に適していない環境だということになります。(ただしそのような環境は滅多にありません)
正常に処理が終了したら、カレントディレクトリにちょうど512バイトのファイルが作成される筈なのでそれによって成否の判別がおこなえます。読み出しサイズを指定(count指定)していないのに512バイトのファイルが作成されたということは「読み出し位置の指定が正しい」ことの証明になります。加えてスクリプト中では抽出したファイルがNTFSのブートセクタであるかのチェックもおこなっています。(NTFSのブートセクタでないと判明した場合もファイルは削除していません。また、基本領域・論理領域双方に対応しています。)
正常に処理が終了した場合は抽出したPBRイメージファイルを壊れたPBRに上書きする為のddコマンドの構文が出力されます。それに従って例えば次のようにddコマンドを実行すれば修復が完了します。
# dd if=backuped-sda1-pbr.img of=/dev/sda1
ソース (かなり簡単です)
#!/bin/bash -e if [ $# -lt 1 ]; then echo "eg. $0 /dev/sda1" exit 1 fi LANG=C DEVICE=$1 common=${DEVICE%/*} devname=${DEVICE##*/} left3char=$(echo ${devname}|cut -b1-3) devicenumber=$(echo ${devname}|cut -b4-) DISK=${common}/${left3char} echo "Target Disk :${DISK}" echo "Target Partition :${DEVICE}" outputfile=backuped-${devname}-pbr.img firstsector=$(fdisk -lu ${DISK}|grep "${DEVICE} "|sed 's/\*//'|awk '{print $2}') lastsector=$(fdisk -lu ${DISK}|grep "${DEVICE} "|sed 's/\*//'|awk '{print $3}') fsid=$(fdisk -lu ${DISK}|grep "${DEVICE} "|sed 's/\*//'|awk '{print $5}') if [ "${fsid}" != "7" ]; then echo "Error, ${DEVICE}: Id is not 07" exit 1 fi echo "firstsector :${firstsector}" echo "lastsector :${lastsector}" sectors=$((${lastsector} - ${firstsector} +1)) echo "total sectors :${sectors}" skipsectors=$((${sectors} -1)) echo "skipsectors :${skipsectors}" echo echo "Extracting backuped PBR..." dd if=${DEVICE} of=${outputfile} bs=512 skip=${skipsectors} >/dev/null 2>&1 filesize=$(stat -c %s ${outputfile}) echo if [ ${filesize} -eq 512 ]; then if (file ${outputfile}|grep -q "NTFS") then echo "Finished, ${outputfile} is here." echo "You may execute \"dd if=${outputfile} of=${DEVICE}\"" elif (file ${outputfile}|grep -iq "x86 boot sector") then if (strings ${outputfile}|grep -iq "NTLDR is missing") then echo "Finished, ${outputfile} is here." echo "You may execute \"dd if=${outputfile} of=${DEVICE}\"" fi else echo "Error, Not a NTFS boot sector" exit 1 fi else echo "Error, filesize :${filesize}" fi
(余談)
誤ってパーティションテーブルを壊してしまったときなどに「パーティションテーブルの修復」が出来れば便利です。以前からgpartという修復を助けるソフトウェアがあるにはありますが、完全なものとは言えません。もし私がパーティションテーブルの修復をする羽目になったら、そしてそのハードディスクがNTFSとFATだけで使用していたなら、私は自分でgpartの代わりにパーティションテーブルの修復を助けるシェルスクリプトを作ると思います。HSの値を仮定してやれば、PBRの位置は絞られますから、シェルスクリプトで十分に探索が可能です。(NTFSとFATのPBRは非常に特徴的ですから)拡張領域も含めて全てのパーティション情報を復元できると思います。※
但し、私はそんな羽目にならないようにパーティションテーブルの情報は日頃から確実にバックアップをとっています。いつ何時マイナーなOSのインストーラがパーティションテーブルを壊すかもしれないと思うからでもあります。テキスト情報ですから場所も殆ど必要ありません。
※ (2008-12-16)試験的ににごく簡単な"パーティションテーブルを推量するシェルスクリプト"を作成しました。実際のパーティションテーブルの修正はおこなわないので修復スクリプトとは呼べません。あくまで推量スクリプトです。fdiskとの親和性の高い出力をおこないますので、gpartよりも役に立つこともあると思います。NTFS,FATおよびGRUBのブートセクタを検出することでパーティションテーブルの推量をおこないます。勘のいい人は気づいたかもしれませんが、2段階ブートに統一して、Linux OSのパーティションの先頭にGRUBをインストールしていると、パーティションテーブルの推量(および修復)に有利です。次にこのスクリプト(ツール)の制限を挙げます。gpartなんかと同様な制限なのですが、NTFS,FATおよびGRUBのブートセクタを見逃すことはないのですが、構成変更をおこなった経験のある古いハードディスクなんかだと過去に使われていたブートセクタを誤検出してしまうことがあります。ただしこれは当然仕方のないことです。(2008-12-30)本質的には何も進歩していないのですが、細々と変更をおこなっています。
(余談2)
このスクリプトではパーティションテーブルは参照するだけで更新はしないのでfdiskコマンドを使用しています。シェルスクリプトでパーティションテーブルを更新する場合にはsfdiskコマンドを使用します。
(おまけ)
上のスクリプトからechoとかFSIDのチェックを削除して、単純に指定パーティションの末尾のセクタを抽出する機能だけを持つスクリプト(もちろん上と同じく、シリンダ境界に沿って確保されているパーティションにのみ対応)(基本領域・論理領域双方に対応していますが、出力する意味のないIdが5とかfの領域を除外する処理は組み込んでいません)
#!/bin/bash -e if [ $# -lt 1 ]; then echo "eg. $0 /dev/sda1" exit 1 fi LANG=C DEVICE=$1 common=${DEVICE%/*} devname=${DEVICE##*/} left3char=$(echo ${devname}|cut -b1-3) devicenumber=$(echo ${devname}|cut -b4-) DISK=${common}/${left3char} outputfile=lastsector-${devname}.img firstcylinder=$(fdisk -l ${DISK}|grep "${DEVICE} "|sed 's/\*//'|awk '{print $2}') lastcylinder=$(fdisk -l ${DISK}|grep "${DEVICE} "|sed 's/\*//'|awk '{print $3}') cylinders=$((${lastcylinder} - ${firstcylinder} + 1)) st=$(fdisk -l ${DISK}|grep "sectors/track"|awk '{print $3}') sc=$(fdisk -l ${DISK}|grep "cylinders of"|awk '{print $5}') if [ ${devicenumber} -le 4 ]; then sectors=$((${cylinders} * ${sc})) else sectors=$((${cylinders} * ${sc} - ${st})) fi if [ ${firstcylinder} -eq 1 ]; then sectors=$((${sectors} - ${st})) fi skipsectors=$((${sectors} -1)) dd if=${DEVICE} of=${outputfile} bs=512 skip=${skipsectors} >/dev/null 2>&1 filesize=$(stat -c %s ${outputfile}) if [ ${filesize} -eq 512 ]; then echo "Finished, ${outputfile} is here." else echo "Error, filesize :${filesize}" fi
(2009-12-15追記)こちらも是非お読み下さい。
NTシグニチャがどこにあるのかを日本語で検索すると、「NTシグニチャのクリアとはMBRの438バイト目から9バイトをすること」であるとの情報が始めの方にいくつか見つかると思います。これらは過去に私が書いたもので、実は厳密ではない情報です。MBRのそのあたりはNTシグニチャ以外の用途に使われていないので、9バイトだと思っていても支障が生じるわけではないのですが、正確にはその9バイトの中間あたりの(441バイト目からの)4バイトが厳密なNTシグニチャです。
NTシグニチャを書き込むスクリプト(ツール)は提供しません。パーティション構成の異なるディスク間で無理にNTシグニチャをコピーするとWindowsによってパーティションテーブルが破壊される事故が起きる場合があるからです。NTシグニチャのコピーなどは試みずに気軽にNTシグニチャをクリアすることをお薦めします。NTシグニチャをクリアするとドライブレターを振り直す必要が生じますが、事故に遭うよりはマシです。←(2013-6-11追記)このような“事故”はWindows 2000で発生しました。“現役”OSでは発生しません。パーティションを割り直した際には必ずNTシグニチャをクリアするというのが最も安全なハードディスクの使い方だと言えると思います。(同じディスクを複数のPCに取り付けたり頻繁にパーティション割りの変更をおこなったりする人以外は殆ど気にしなくてもいいレベルの話ではありますが...)
このスクリプトを実行すると
# "clear-disk_identifier(ntsig).sh" /dev/sda Current Disk identifier(NT Signature): 0xe4cee4ce Proceed? yes or no [n]
このように現在のNTシグニチャの値が表示された上で確認を求めてきます。
ダウンロード clear-disk_identifier(ntsig).sh
[clear-disk_identifier(ntsig).sh]
#!/bin/sh -e if test $# -lt 1; then echo "eg. $0 /dev/sda" exit fi echon() { printf "%s" "[email protected]" } yesno() { msg="$1" def="$2" while true ; do echon "$msg" read answer if [ "$answer" ] ; then case "$answer" in y|Y|yes|YES) return 0 ;; n|N|no|NO) return 1 ;; *) echo " " echo "Error: Invalid response, expected \"yes\" or \"no\"." continue ;; esac else return $def fi done } printntsig() { echo -n "Current Disk identifier(NT Signature): 0x" hexdump -s 442 -n 2 $1|head -1|cut -d" " -f2|tr -d '\12' hexdump -s 440 -n 2 $1|head -1|cut -d" " -f2 } bsig=`hexdump -s 510 -n 2 $1|head -1|cut -d" " -f2|tr -d '\12'` if test "$bsig" != "aa55"; then echo "Not a Valid Boot Sector" exit fi printntsig $1 if yesno "Proceed? yes or no [n] " 1 ; then dd if=/dev/zero bs=1 seek=440 count=4 of=$1 >/dev/null if test $? -eq 0; then echo "Done" printntsig $1 fi fi
上の機能を表示のみに絞った版です。
#!/bin/sh -e if test $# -lt 1; then echo "eg. $0 /dev/sda" exit fi echo -n "Disk identifier(NT Signature): 0x" hexdump -s 442 -n 2 $1|head -1|cut -d" " -f2|tr -d '\12' hexdump -s 440 -n 2 $1|head -1|cut -d" " -f2
(2007-12-29) 以前から告知のとおり、シェルスクリプトでやるべき処理ではないので削除しました。
※: ところでシェルスクリプト内のループでパイプを使うとパイプ以降(つまりループの中など(詳細は略))が別プロセスとなり、ループ内の変数値をループの外に伝えることはできません。そういう場合の一つの解決策は関数化です。ありきたりのサンプルが→ここにあります。
また、ヒアダイレクトを使ってシェルスクリプト内で新たなスクリプトなどを作成する例なんかがこのページにあります。
※:上の検索窓で「/bin/sh」を検索すれば当サイト内のシェルスクリプトを含むページが全て見つかります。
eucJPとかutf-8な環境で中身がsjisのファイル群を日本語grepする為に作成したものです。
Webを検索せずに作ったので、他の人がこのような要件でどうしているかは知りません。
※これはutf-8環境用です。eucJPの場合は最後2行が異なります。
(2007-5-15)数ヶ月前に知りました。このような用途には以前から有名なPerlスクリプトがあるようです。
殆ど使ったことがないのですが、人によっては何かの助けになるでしょう。
(2008-3-1)放ったらかしにしていましたが、修正しました。
#!/bin/sh LANG=ja_jp.SJIS TMPC= OPTS= PATTN= FILES= parse_args() { for i in "[email protected]" ; do if [ "$i" == "-" ]; then OPTS=${OPTS}" "${i} shift PATTN=${1} shift FILES="[email protected]" return fi TMPC=`echo - ${i}|cut -b 3-3` if [ ${TMPC} != '-' ]; then PATTN=${1} shift FILES="[email protected]" return fi OPTS=${OPTS}" "${i} shift done } parse_args "[email protected]" PATTN=`echo "${PATTN}"|iconv -f UTF-8 -t CP932` grep ${OPTS} "${PATTN}" ${FILES}|nkf -Sw
使わないので削除します。(2008-11-29)
勝手のわからないOSで/以下を全て検索したりするときに使っています。※検索語の後にgrepに渡すオプションを付けます。
[textsearch.sh] (2008-12-3)最近のfileコマンドの仕様に合わせてアップトゥーデートしました。
#!/bin/sh if [ $# -lt 1 ]; then echo "$0 SearchWord [Grep Option(eg. -i)]" exit 1 fi exitproc() { rm -f ${TMPFILE}; } trap ' exitproc exit 1 ' 2 15 SEARCH=$1 OPTION="-n $2" TMPFILE=/tmp/$USER.grepwords cat>$TMPFILE<<EOT text XML EOT echo -n "Current Path:" echo `pwd` echo "search word:${SEARCH}" echo "Option:${OPTION}" echo && echo && echo && echo find . -type f|while read -r i do file "${i}"|grep -f $TMPFILE> /dev/null && echo "${i}" done|while read -r i do grep ${OPTION} "${SEARCH}" "${i}" && echo "${i}" \ && echo && echo && echo && echo done exitproc echo -en '\a'>&2
通常、私はこのスクリプトをエディタ上で実行します。結果を取り込み、検索されたファイルに次々ジャンプします。
仮想端末やファイルブラウザ上でfirefoxでhtmlファイルを簡単に開くことができるようにするスクリプト
(2006-9-15) 最近のfirefoxでは不要であることに気づきました。
(2007-7-9) 削除しました。
ダウンロード download-radio.sh 2011-4-19更新
説明・中身を見るならこちら
ダウンロード all-process-asx.sh 2011-4-19更新 このスクリプトは単独では動きません。必ず説明ページで他に必要なスクリプトを一緒にダウンロードして下さい。
説明・中身を見るならこちら
ダウンロード download-nhk-gogakukouza.sh
説明・中身を見るならこちら
(2009-12-1追記)以下の説明はこのスクリプトを単独で使用する場合用です。このスクリプトを部品として利用するもっと便利なものがこのページにありますので、そちらもご覧下さい。
大げさな説明をすると、Windows上でGetASFStreamやNet Transportを使ってやれることをLinux上で可能とするスクリプトです。もちろんこの説明は大げさすぎで、本スクリプトは貧弱な機能しか持っていません。しかしLinux上で、しかもコマンドラインで利用できることが特徴(強み)です。
最近はポッドキャストやフラッシュを採用しているサイトが多くなってしまいWindows Media形式でストリーミングしているサイトは少ないと思います。NHKラジオの英会話はフラッシュ形式なのでこのスクリプトは使えません。
とりあえずこのスクリプトが使えるURLをいくつか挙げておきます。私にとってはめぼしい内容の放送が乏しいのでこのスクリプトの使いどころが今はあまりないという感じです。(2014-6-23)以下の例文で使用しているURLは2013年に廃止され、それらコンテンツはyoutube化されました。youtube化されたコンテンツの自動ダウンロードにはdownload-youtube.shをお使い下さい。
MBSラジオのありがとう浜村淳です(平日毎日更新)![]() | mms://mbs.sswmt1.smartstream.ne.jp/mbs/arigatou/arigatou[MMDD].wma |
MBSラジオの押尾コータローの押しても弾いても(週一更新)![]() | mms://mbs.sswmt1.smartstream.ne.jp/mbs/oshio/oshio.wma |
MBSラジオのヤングタウン日曜日(出演笑福亭鶴瓶、週一更新)![]() | mms://mbs.sswmt1.smartstream.ne.jp/mbs/yannichi/yannichi_[MMDD].wma |
(2011-10-16追記)NHKラジオに関する情報は削除しました。NHKラジオのストリーミング放送に関してはこちらのページを利用して下さい。
このスクリプトはクーロンで定期的に起動してストリーミング放送を自動的にサーバ上に保存していく為のものです。
平日更新の放送であれば、たとえばcrontabに
00 17 * * 1-5 export PATH=$PATH:/home/disklessfun/bin; (実際には改行しない) download-wma.sh (実際には改行しない) mms://mbs.sswmt1.smartstream.ne.jp/mbs/arigatou/arigatou`date '+\%m\%d'`.wma (実際には改行しない) /somewhere > /somewhere/download-arigatou-`date '+\%Y\%m\%d\%H\%M'`.log 2>&1
と設定し、
週一更新の放送であれば、たとえばcrontabに
00 20 * * 2 export PATH=$PATH:/home/disklessfun/bin; (実際には改行しない) download-wma.sh (実際には改行しない) mms://mbs.sswmt1.smartstream.ne.jp/mbs/oshio/oshio.wma (実際には改行しない) /somewhere >/somewhere/download-oshio-`date '+\%Y\%m\%d\%H\%M'`.log 2>&1
とか
00 20 * * 3 export PATH=$PATH:/home/disklessfun/bin; (実際には改行しない) download-wma.sh (実際には改行しない) mms://mbs.sswmt1.smartstream.ne.jp/mbs/yannichi/(実際には改行しない) yannichi_`date -d '3 days ago' '+\%m\%d'`.wma (実際には改行しない) /somewhere >/somewhere/download-yannichi-`date '+\%Y\%m\%d\%H\%M'`.log 2>&1
と設定しておくというわけです。同じURLのままで定期的に内容が変わってしまうストリーミング放送の聞き逃し対策として有効だと思います。
このスクリプトを使用する為にはmplayerとlameをインストールしておく必要があります。更にget-wma-info.plスクリプトをパスの通った場所に置いておく必要があります。
言うまでもないことですが、ダウンロードして作成したファイルを自分で使用する限りは著作権法に全く違反しません。
現在NHKからダウンロードできるwmaにはヘッダにタイトルが書き込まれていないようです。その場合のローカルでのファイル名を決定する仕様はソースを参照して下さい。ソースは名前なしパイプの使用例でもあります。
(2009-9-15追記)簡単な重複ダウンロード・チェック機能を追加しました。
(2009-12-01追記)このページ用に大幅に改良しました。改良点の一つにWMA内の日本語タイトルに対応したことが挙げられます。
ダウンロード download-wma.sh 2014-6-23更新(内部で使用しているコマンドをmplayerからmplayer2に変更(これに伴い名前付きパイプの使用を廃止)。ファイル名無害化関数に%の処理を追加) 2012-4-2更新(スキップ部に-rfの記述を追加) 2012-3-11更新(asfbinコマンドを用いてWMVにインデックスを付加する記述を追加) 2010-3-28更新
※動作には下に掲載のget-wma-infoが必要
別の説明はこちら
ダウンロード transcode-wma-to-mp3.sh 2014-6-23更新(内部で使用しているコマンドをmplayerからmplayer2に変更(これに伴い名前付きパイプの使用を廃止)。ファイル名無害化関数に%の処理を追加) 2010-3-28更新
これの機能省略版で、このページの為に掲載しているだけです。
説明はもう少しこちらにも
こちらで使用しています。
使用する為にはPerlのAudio::WMA拡張モジュールをインストールしておく必要があります。
Ubuntu系なら
# apt-get install cpanminus # cpanm Audio::WMA
でインストールできます。
ダウンロード get-wma-info.pl パスの通った場所に置いて下さい。
[get-wma-info.pl]
#!/usr/bin/perl use strict; use Audio::WMA; my $type = $ARGV[0]; my $item = substr($ARGV[1],1); my $file = $ARGV[2]; unless ( -e "$file" ) {die;} my $wma = Audio::WMA->new($file); if ($type eq "-info"){ my $info = $wma->info(); print "$info->{$item}"||die; } elsif ($type eq "-tags"){ my $tags = $wma->tags(); print "$tags->{$item}"||die; }
試験的に作成したパーテョションテーブルを推量するシェルスクリプト(パーティションテーブルを修復するための情報を出力するためのスクリプトです。勝手にパーテョションテーブルを書き換えることはしません。)
こちらにまた別の、(詳しいかもしれない)説明があります。
ダウンロード guess-partition-table.sh このスクリプトを最初から組み込んだLinuxがこれです。
#!/bin/bash -e exitproc() { umount $TMPDIR;rmdir $TMPDIR; } trap ' exitproc exit 1 ' 2 15 getrawhs() { set +e hdinfo="$(hdparm -i $DEVICE 2>/dev/null)" if test $? -ne 0; then USERHSMAND=true else set -e for info in $hdinfo; do case "$info" in *RawCHS=*) RawCHS="${info#RawCHS=}"; ;; esac done RawH=$(echo $RawCHS|cut -d"/" -f2) RawS=$(echo $RawCHS|cut -d"/" -f3|sed 's/\,//') fi set -e echo "RawHS=$RawH/$RawS" } analize_sector() { local cylinder=${1} local offset=${2} local start=$((cylinder + 1)) if (file $TMPDIR/$image|grep -iq "x86 boot sector") then if (strings $TMPDIR/$image|grep -q NTFS) then type="NTFS Boot Sector" elif (strings $TMPDIR/$image|grep -q MSWIN) then type="FAT Boot Sector" elif (strings $TMPDIR/$image|grep -q GRUB) then type="GRUB Boot Sector" else type= fi if [ $offset -eq -1 -a "$type" == "NTFS Boot Sector" ]; then echo " Cylinder $(($start - 1)) is NTFS End Cylinder" $DEBUG && echo else echo -n "Start-Cylinder $start" echo -en "\toffset $offset" echo -e "\t$type" $DEBUG && echo -n "SectorImage: " $DEBUG && strings $TMPDIR/$image|tr -d '\012' $DEBUG && (echo;echo) fi fi return 0 } DEVICE=$1 if [ $# -lt 2 ]; then if [ $# -gt 0 ]; then getrawhs fi echo "eg. $0 /dev/sda -HS=255/63" echo "eg. $0 /dev/sda -HS=64/32" echo "eg. $0 /dev/sda -HS=16/32" echo "eg. $0 /dev/sda -HS=32/16" echo "eg. $0 /dev/sda -HS=32/32" echo "eg. $0 /dev/sda -HS=16/16" exit 1 fi DEBUG=false USERHSMAND=false HS=$2 devname=${DEVICE##*/} LANG=C # User specified HS for x in $2; do case "$x" in *-HS=*) hs="${x#-HS=}"; ;; esac done H=$(echo $hs|cut -d"/" -f1) S=$(echo $hs|cut -d"/" -f2) #H=${H:-$RawH} #S=${S:-$RawS} test "$S" = "" && exit cylindersize=$(($H * $S)) wholesize=$(cat /sys/block/$devname/size) cylinders=$(($wholesize / $cylindersize)) TMPDIR=`mktemp -d` mount -t tmpfs -o "size=100k" tmpfs $TMPDIR echo "Target Device: $DEVICE" echo "Total Cylinders: $cylinders" echo "H/S=$H/$S" echo for ((i=0;i<$cylinders;i++)) do skipsectors=$(($i * $cylindersize )) if [ $i -eq 0 ]; then skipsectors=$(($skipsectors + $S)) fi skipsectors=$(($skipsectors - 1)) dd if=$DEVICE count=1 of=$TMPDIR/1.img skip=$skipsectors 2>/dev/null skipsectors=$(($skipsectors + 1)) dd if=$DEVICE count=1 of=$TMPDIR/2.img skip=$skipsectors 2>/dev/null skipsectors=$(($skipsectors + $S)) dd if=$DEVICE count=1 of=$TMPDIR/3.img skip=$skipsectors 2>/dev/null image=1.img analize_sector $i -1 image=2.img analize_sector $i 0 image=3.img analize_sector $i $S done exitproc exit 0
zipのmanってわかりにくいですよね
でもWindowsのアーカイバと同じように圧縮するだけなら↓これだけです。
$ zip -r foo[.zip] foo
ついでにunzipコマンドの(少し古い)ラッパースクリプトを掲載しておきます。
最近のunzipにもこのようなものが必要かどうかは調べていません。
Windows上で作成した複数のzipファイルをsambaサーバ上で連続して解凍するためのものです。
※Windowsで圧縮したzipファイルを扱えるようにsmbfnconvコマンドを使用しています。内部SJISのzipファイルであればわりと正しくファイル名の文字コードを変換できます。smbfnconvを使わない仕様をデフォルトへと変更しました。
[unzip.sh]
#!/bin/sh [ $# -lt 1 ] && echo "usage: $0 [-m(--mkdir)] zip-file(s)" && exit # Normal color NORMAL="[0;39m" # BLUE: Warning mesages BLUE="[1;34m" MKDIR=false while [ -n "${1}" ] do case "${1}" in -m|--mkdir)MKDIR=true;shift;; -)shift;break;; *)break;; esac done while [ -n "${1}" ] do if (file "${1}"|grep -iq "Zip archive") then dirname=`dirname "${1}"` basename=`basename "${1}"` filename=`basename "${1}" .zip` if [ "${filename}" != "${basename}" ]; then # $MKDIR && unzip -d "${dirname}/${filename}" "${1}" && \ # smbfnconv -f cp932 -t utf-8 "${dirname}/${filename}" $MKDIR && unzip -d "${dirname}/${filename}" "${1}" ! $MKDIR && unzip "${1}" else echo "${BLUE}Warning: ${1} does not have .zip extension." echo "Do nothing.${NORMAL}" fi else echo "${BLUE}Warning: ${1} is not Zip archive.${NORMAL}" fi shift done
言うまでもないと思いますが、SJIS対応のunzipコマンドを使用する場合はsmbfnconvを記述している行の代りに、1行下の、現在コメントアウトしている行を使います。
スクリプトというより、よく使うコマンドを書き出しただけとも言えます。
ファイルブラウザに登録して使用するものを除けばaliasに登録するだけでもいいと思います。
最近はdev=・・は要りませんが、まあ記録の意味で...
cdrecord -v dev=ATA:1,0,0 -dao -eject "${1}"
(2015-10-29)BD環境にも対応する為/dev/dvdを/dev/cdromに修正(実デバイスは大概/dev/sr0)
growisofs -dvd-compat -Z "/dev/cdrom=${1}"
※:growisofsコマンドの大きな特徴はスマートにオンザフライに対応していることだと思います。ここでそのやり方を紹介しないのは私のメインマシンのCPU負荷が普段は高くてそのやり方をあまり使っていないからです。でも他のPC上でのバックアップの際にはgrowisofsを用いたオンザフライ焼きを活用しています。
あと、現状、LinuxでBDを焼く場合には上記growisofsの引数に「-use-the-force-luke=spare:none」を加えるのが普通です(理由説明は省略)。
最近はdev=・・は要りませんが、まあ記録の意味で...
cdrecord -v dev=ATA:1,0,0 blank=fast -eject
dvd+rw-format -blank /dev/dvd
ファイルブラウザ上でWindowsのインターネットショートカット(urlファイル)をダブルクリックするとfirefoxが当該ページを開いて起動します。※拡張子がurlのファイルの扱いについてファイルブラウザに登録しておく必要があります。仮想端末上でも使用できます。
$ firefoxlnk.sh hoge.url
みたいな感じで使用します。
exec firefox `egrep "^URL" "${1}"|cut -b 5-` &
残念ながら現在はhttpsに対応する為にワンライナーはやめました。
#!/bin/bash line=$(egrep "^URL" "${1}") exec firefox "${line#*=}"
生ペグDVD作成用等に使用しています。ファイルが入ったディレクトリを引数に取ります。(最近は-Jオプションは不要だと思うので私は使用していません)
(2008-12-30)最初のチェックは、今のところ互換性に問題のあるgenisoimageを使いたくないので設けてあります。
(2010-2-6)自分でも忘れていたのですが、自分で使用しているバージョンではファイル名が完全に保存されたかをチェックする機能を追加していました。ワンライナーの範疇から大きく逸脱しますがそのバージョンを紹介しておきます。
(2015-1-13)もう(とうの昔に)互換性の問題はほぼ心配しなくていいので(mkisofsの代わりに)genisoimageを使用する版に差し替えました。
#!/bin/sh -e # Needed settings in /etc/sudoers. #yourname ALL=(ALL) NOPASSWD: /bin/mount #yourname ALL=(ALL) NOPASSWD: /bin/umount genisoimage -V "$1" -allow-limited-size -r -o "$1.iso" "$1" TMPFILE1=`mktemp` TMPFILE2=`mktemp` TMPDIR=`mktemp -d` (cd "$1";ls -R>$TMPFILE1) sudo mount -o loop,ro "$1.iso" $TMPDIR (cd $TMPDIR;ls -R>$TMPFILE2) sudo umount $TMPDIR rmdir $TMPDIR set +e diff -u $TMPFILE1 $TMPFILE2 RET=$? set -e if test ${RET} -ne 0 ; then echo "Error, At least one filename was not preserved." fi rm $TMPFILE1 $TMPFILE2 exit ${RET}
(2008-12-30)この方法は特に互換性が低くて、Windows XP,Windows 2000で中身を読めない(Vistaは知らない)ので、私としては、サイズが4096Mバイト以上4488Mバイトのファイルを分割せずに焼く場合専用の方法として使っています。4488Mバイト超のファイルの場合は1層に入りきらなくてどうせ分割が避けられないのでこの方法は使いません。この方法で作成したDVDはLinuxでLinuxでもWindowsでも読めます。私の場合Linux環境が常に近くにあって、分割したものを結合する手間よりもWindowsで読めないものをLinuxで読む手間の方が軽いのでこの方法を採用できています。(2010-03-04追記)久しぶりにこのオプションを利用してDVDを焼き、Windowsで読めるか試したところ、少し古い環境と言えるWindows 2000+BHA B's Recdorder 8.67の環境でも問題なく読めました。以前Windowsで読めなかったのは当時のgenisoimageの実装に問題があった為ではないかと思います。
#!/bin/sh genisoimage -V $1 -allow-limited-size -r -o $1.iso $1
シュリンク後、DVDを再作成する際に使用しています。
(2007-5-15)ファイル名は自分の命名ルールに素直に従ってつけたものです。同名の有名なスクリプトと内容に関連はありません。
(2008-12-30)最初のチェックは、今のところ互換性に問題のあるgenisoimageを使いたくないので設けてあります。
#!/bin/sh if test -L `which mkisofs`; then echo "mkisofs is Symbolic Link" && exit fi mkisofs -V "$1" -dvd-video -o "$1.iso" "$1"
$ readline.sh [ファイル名] [数字]
といった感じで使用します。
#!/bin/sh count=0 while read i do count=`expr $count + 1` [ $count -eq $2 ] && echo $i done<$1
シェルスクリプトでやるとなると一応こうなると思いますが、行頭・行末がトリムされてしまうので通常はperlやawkを使うと思います。
これは他と違い、単に構文の紹介だけです。どこにでも転がっているようなものだと思います。
for i in *.JPEG;do mv "$i" "`basename "$i" JPEG`jpg";done
高機能シェルだと内部コマンドだけで可能です。でも基本形はこんなものではないかと思います。
"chgext"みたいな名前で、2つの引数をとるシェルスクリプトにしてもいいでしょう。
MODTIME=`stat -c %y "$1"|sed 's/\-/\//g'|cut -b1-19` touch -t `date -d "$MODTIME 32400 seconds" "+%Y%m%d%H%M.%S"` "$1"
ずらす時間を自由に指定できるスクリプトとして使用する場合は32400の部分を$2にします。
※:9時間後ろにずらすなら"32400 seconds"とか"9 hours"を指定し、9時間前にずらすなら、"32400 seconds ago"とか"9 hours ago"を指定すればいいわけです。
多分同じ働きをするスクリプトはどこにでも転がっていると思いますが、これは独自に作成したものなので何らかの価値があるかもと思い掲載することにします。但しこれは下のchgcase.shを呼び出すだけです。オプションの指定が必須なのは安全装置の代わりです。
#!/bin/sh [ $# -lt 1 ] && echo "$0 -u|-l" && exit 1 case "${1}" in -u|-l);; *) echo "$0 -u|-l" && exit 1 ;; esac find . ! -name "."|sort -r|while read i do chgcase.sh "${1}" "${i}" done
何故、bashの機能を使っているか?ですが、後半のechoで"renaming.."と出力していている個所でfromとtoでパス表記の違いが生じないようにするにはこの方法が一番簡単だと思ったからです。
#!/bin/bash [ $# -lt 2 ] && echo "$0 -u|-l filename" && exit 1 UPPER=false case "${1}" in -u)UPPER=true;; -l);; *) echo "$0 -u|-l filename" && exit 1 ;; esac fname=${2##*/} dirpath=${2%*/*}/ [ "${fname}/" == "${dirpath}" ] && dirpath="" $UPPER && newfname=$(echo "${fname}"|tr \'[a-z]\' \'[A-Z]\') ! $UPPER && newfname=$(echo "${fname}"|tr \'[A-Z]\' \'[a-z]\') if [ "${newfname}" != "${fname}" ]; then echo "renaming \"${2}\" as \"${dirpath}${newfname}\"" mv "${2}" "${dirpath}${newfname}" fi