bash でディレクトリ変数の展開を有効にする direxpand を設定する方法

Ubuntu 22.04 から、ターミナルでの変数を使ったディレクトリ移動が厄介になりました。

例を挙げます。

FSLのインストールパス は変数 $FSLDIR に入っています。私はこれまでは、$FSLDIR/standard にアクセスしたい場合

cd $FSLDIR までタイプしたら、その後、タブキーをタイプすると、シェルが自動で cd /usr/local/fsl と変数を展開してくれて、その後のディレクトリをタイプしていました。

しかし、Ubuntu 22.04 から、同じことをすると

cd \$FSLDIR/

と変数がエスケープされてしまい展開されなくなってしまいました。

これは不便です。

調べたところ、shopt というコマンドがあることを知りました。

続きを読む

Linuxで特定の時間より後に生成されたファイルを列挙する方法

画像解析などをしていると、しばしば、「今の作業で新しくできたファイルは何だろう?」と思うことがあります。

Linuxでは、find コマンドに、-newer というオプションがあります。findのmanページには以下の記載があります。

-newer file
ファイルが file よりも最近に内容を更新されていれば、真を返す。

であるならば、あるファイルを作成して、作業をして、その後に、findをかければ列挙できるはずです。

いろいろ調べた結果、touchコマンドで -t オプションを使うとタイムスタンプを決められるので、それをスクリプトに組み込めるなと思いました。

以下のスクリプトで、新たに生成されたファイルの一覧が generated_from_タイムスタンプ.txt に作成されます。

#!/bin/bash

#generate timestamp
ts=$(date +%Y%m%d%H%M.%S)

#generate a temporary file with current timestamp for find
touch -t $ts /tmp/_timestamp

# BEGIN commands to generate new files
#
# END

# list files which is generated after /tmp/_timestamp
find . -type f -newer /tmp/_timestamp | tee -a generated_from_${ts}.txt

Bashの様々な設定は、.bashrc ではなく .bash_aliases に書くと事故が防げる

先日、あるスクリプトを書いている中、.bashrcに追記する内容を書いた時に

echo "something" >> ~/.bashrc

と書くべきものを

echo "something" > ~/.bashrc

と誤って書いてしまい、テストでスクリプトを走らせて .bashrc を確認したところ、

something

の一語だけになっており、顔から血の気がひくという経験をしました。

続きを読む

Ubuntu上のFSLやFreeSurferでsyntax errorが出る時の対処法

Ubuntu上でFSLやFreeSurferを走らせる時、

Syntax error: "(" unexpected.

といったエラーが出ることがあります。

この原因を探っていたらわかったことがありました。

FSLのプログラムは、基本、bashで動くことを前提にしていますが、ファイルの冒頭のShebang行は、#!/bin/shとなっています。

RedHatやCentOSは、/bin/sh は、bashにシンボリックリンクが張られていますが、
Ubuntuでは、dashにシンボリックリンクが張られています。
ls -l で確認するとすぐに確認できます。

$ ls -l /bin/sh
lrwxrwxrwx 1 root root /bin/sh -> dash

dashとbashは完全に互換性がないため、ときにbashの文法が通用しないことがあります。

解決策は以下の2つです。

  1. シェルスクリプトのShebang行を #!/bin/bash に変更する
  2. 自分でシェルスクリプトを書く場合などはこれがいいでしょう。
    しかし、FSLでは、300以上のスクリプトがありますので、これを全部変えるのはめんどくさいですね。

  3. dpkg-reconfigureで、dashをbashに変更する
  4. Ubuntuでは、 dpkg-reconfigure dash というコマンドで、dashを使わずにbashを使うようにすることができます。

    インタラクティブに行うには、以下のコマンドを叩きます。

    $ sudo dpkg-reconfigure dash
    

    すると、次の画面が出るので、「いいえ」を選びます。

    再度、/bin/shのシンボリックリンク先を確認してみます。

    $ ls -l /bin/sh
    lrwxrwxrwx 1 root root /bin/sh -> bash
    

    今度はbashに変更されていることがわかります。

    なお、インタラクティブでなく変更したい際は、以下で行います。
    いくつかのサイトで情報が提供されていましたが、正しくないものもありましたので、試行錯誤した結果、以下が最適な解決法とわかりました。

    echo "dash dash/sh boolean false" | sudo debconf-set-selections
    sudo dpkg-reconfigure --frontend=noninteractive dash
    

bashのtips: 直前の引数を利用したいときは !$ もしくは Esc + .

私はこんな作業をよくします。

  • あるファイルをディレクトリAにコピー
  • ディレクトリAに移動

この際

$ cp something /path/to/A
$ cd /path/to/A

とするわけですが、この /path/to/A を2回うつのはめんどくさいので、簡単な方法がないかを調べてみると、

!$

という特殊変数があることがわかりました。
しかし、しょっちゅう忘れるので、覚え方を考えてみました。

bashでは、履歴を知りたいときに、!を使います。
たとえば

$ history

でコマンド履歴を調べ、その1457番目のコマンドを再度実行したいときは

$ !1457

とすればいいわけですね。

で、$ですが、正規表現において、$は「行の最後」を意味します。

この2つを組み合わせれば

「履歴において一番最後のもの」

と考えれば、 !$

は覚えやすいなと思いました。

自分の思考過程を備忘録として書いておきます。

<29/July/2020 追記>
コメントに Esc + . でもいけるというご指摘をいただきました。

これは、viの動作をイメージすると覚えやすいですね。
vi は コマンドモードで、. は繰り返しになるわけですので、
bashでEscでviのコマンドモードに入ったような感じになって、.で前回の引数の繰り返しというイメージで覚えたらいけそうです。

BashからMatlabスクリプトを実行する方法

先日、ある方と「BashからMatlabを呼び出せないだろうか」という話をしていました。もし、これができたら、シェルスクリプトから、Matlabを呼び出せるので、シェルとMatlabを完全に連携できるわけです。

結論としては、以下でできました。

  • Short answer
  • Matlabのスクリプト名を sample_code.m とすると、以下でできます。

    $ matlab -nodesktop -nosplash -r 'sample_code; exit'
    

    コツは2つです。

  • スクリプト名ではなく、コマンドとして指示するため、.mは外す
  • Matlabから抜けるために exit を追加する

続きを読む

Linuxでfind, sedを使いながら文字列を再利用してファイル名の途中に文字列を挿入する方法

最近、以下のようなことをやる必要がありました。

ファイル名が

201105_ID.jpg
20120608_ID.jpg
20130704_ID.jpg
201409_ID.jpg

となっているファイル(年月が必ずあり、日が時についている)に対して、
年の後にアンダースコアを入れたい、つまり、

2011_05_ID.jpg
2012_0608_ID.jpg
2013_0704_ID.jpg
2014_09_ID.jpg

としたいわけです。

続きを読む