【AS/400】QShellの使い方

# QShellとは

OS/400に標準で用意されているシェル。
これを使うことで、UNIXコマンドを利用した強力なテキスト編集を行ったり、効率的にIFSを運用することができる。
また、ILE-CやJavaをOS/400上で動かすことに利用できる。

# シェルの基礎

## コマンドの連結

コマンド1 ; コマンド2 ： コマンド1に続いてコマンド2を実行する
`> pwd; ls`

コマンド1 && コマンド2 ： コマンド1が正常に終了したときのみコマンド2を実行する
`> ls pwd && ls`

コマンド1 || コマンド2 ： コマンド1が正常に終了しなかった場合のみコマンド2を実行する
`> cat hoge || echo "file not found"`

## ヒアドキュメント

終了文字が入力されるまで、標準出力に入力を続ける。

```
> cat << 'EOF'
  >
> Hello
  >
> QShell
  >
> EOF
  Hello
  QShell
```

## シェル変数と環境変数

シェルで設定できる変数のうち、シェルが終わると消えてしまう変数をシェル変数。
シェルが終わっても残る変数を環境変数という。

envコマンドを引数なしで実行することで、定義されている環境変数を一覧できる。
また、setコマンドを引数なしで実行することで、定義されている環境変数とシェル変数を一覧できる。

```
> HOGE=FUGA
  $
> echo $HOGE
  FUGA
```

## 引用符

### シングルクォート(')

引用符内を文字列として扱う。

### ダブルクォート(")　 

引用符内に変数があればその内容を展開する。

### バッククォート(`)

引用符内にコマンドがあればそれを実行する。
変数があればその内容を展開し、コマンドとして実行する。

### 使用例

```
> CMD=pwd
> echo '$CMD'
$CMD
> echo "$CMD"
pwd
> echo `$CMD`
/tmp
```

# QShellを起動する

`STRQSH`か`QSH`のどちらかのCLコマンドで起動できる。

ホームディレクトリが作ってあれば、OS/400ログインユーザ名のホームディレクトリをカレントディレクトリにした状態でQShellが起動する。

# QShellの操作

## 機能キー

* F3 : 終了  
QShellのセッションを完全に終了
* F6 : 印刷  
ターミナルを印刷
* F9 : コマンドの複写  
押すたびに前回入力したコマンドを表示する
* F11: 桁折返しの切り替え  
表示の折り返しを行うかどうかを切り替える
* F12: 切断  
QShellのセッションを中断する。再度STRQSH(またはQSH)コマンドを実行することで復帰できる。
* F13: 消去  
標準出力をクリアする
* F17: 先頭  
標準出力の先頭まで移動
* F18: 最後  
標準出力の最後まで移動
* F19: 左  
桁折り返ししていない場合、表示を左に移動
* F20: 右  
桁折り返ししていない場合、表示を右に移動
* F21: CLコマンド入力  
CLコマンド入力のためのコマンドラインを表示
* 実行キー  
コマンドを実行する
* PageUp、PageDown  
標準出力を上、下にページ単位で切り替える

## その他

実行中のコマンドを中断するにはシステムリクエストの2を使う。

# QShellの設定スクリプト

## /etc/profile

QShell起動時に実行されるスクリプト。
全てのユーザーに共通する設定をこのファイルで行う。
このファイルが存在している場合のみ実行される。

## ~/.profile

QShell起動時、ログインユーザのホームディレクトリにこのファイルがあれば実行される。
`/etc/profile`とは異なりユーザ独自の設定を記述する。

# QShellコマンド

## ajar

JARファイル、ZIPアーカイブファイルを作成・展開する。

```sh
# hoge.csvファイルをZIP化する
> ajar -cM /home/danishi/hoge.zip /home/danishi/hoge.csv
```

## alias

コマンドのエイリアス(別名)を設定する
QShellのセッションを終了するとエイリアスの設定は消える。
毎回使用したいエイリアスは設定スクリプトに記述する。

```sh
> alias lsl='ls -l'
> alias lsl
lsl='ls -l'
> cat /home/DANISHI/.profile
alias lsl='ls -l'
```
## banner

引数の文字列を大きなAAにして表示する

```sh
> banner AS/400                                   
     #     #####        # #         ###     ###   
    # #   #     #      #  #    #   #   #   #   #  
   #   #  #           #   #    #  #     # #     # 
  #     #  #####     #    #    #  #     # #     # 
  #######       #   #     ####### #     # #     # 
  #     # #     #  #           #   #   #   #   #  
  #     #  #####  #            #    ###     ###                                            
```

## cat

ファイルの内容を表示する(conCATenate)

```sh
# hoge.txtの内容を表示
> cat hoge.txt
```

## cd

ディレクトリを移動する(Change Directory)

```sh
# DANILIBのあるディレクトリに移動する
> cd /QSYS.LIB/DANILIB.LIB
# 1つ上のディレクトリに移動する
> cd ..
# 1つ前にいたディレクトリに移動する
> cd -
```

## chmod

パーミッションを設定する(CHange MODe)

```sh
# hoge.txtのパーミッションを764に設定
> chmod 764 hoge.txt
```

## cmp

2つのファイルを1バイトずつ比較する

```sh
# ファイルの内容が同じ
> cmp -s hoge.txt fuga.txt ; echo $?
  0                                  
# ファイルの内容が異なる
> cmp -s hoge.txt piyo.txt ; echo $?
  1                                  
```

## colrm

指定した桁を削除して表示する(COLumn ReMove)

```sh
> cat hoge.txt            
  1234567890              
  abcdefghij              
> cat hoge.txt | colrm 5
  1234                  
  abcd                  
> cat hoge.txt | colrm 5 8
  123490                  
  abcdij                  
```

## compress

ファイルを圧縮する

```sh
# hoge.tarを圧縮してhoge.tar.zを作成。hoge.tarは削除される
> compress hoge.tar
# hoge.tarを圧縮してhoge.tar.zを作成。hoge.tarは削除されない
> compress -c hoge.tar > hoge.tar.z
```

## cp

ファイル・ディレクトリをコピーする(CoPy)

```sh
# hoge.txtをfuga.txtとしてコピーする
> cp hoge.txt fuga.txt
# DANILIB/WKSAVFをカレントディレクトリにコピーする
> cp /QSYS.LIB/DANILIB.LIB/WKSAVF.FILE .
```

## date

日時を表示する

```sh
> date               
  Thu Aug 20 13:20:06
```

## echo

引数の文字列、変数の値を標準出力に表示する。

```sh
# 標準出力に「hello!」と表示
> echo hello!
# 標準出力に環境変数PATHの値を表示
> echo $PATH
```

## env

環境変数を表示する。

```sh
# 設定されている環境変数を全て表示
> env
```

## find

ファイルやディレクトリを検索する

```sh
# /tmpディレクトリ配下の拡張子txtのファイルを全て表示する
> find /tmp -name "*.txt"
  /tmp/hoge.txt
  /tmp/hoge.d/fuga.txt
```

## grep

検索パターンに一致する行を取り出す(Global Regular Expression Print)

```sh
# /tmpディレクトリにあるディレクトリを表示
> ls -l /tmp | grep ^d
# QRPGSRC以下の全てのメンバーのF仕様書の行を出力
> grep '^     F' QRPGSRC.FILE/*.MBR
```

## help

コマンドのヘルプを表示する

```sh
# 全てのヘルプを表示する
> help                                    
  Qshell, V7R1M0 (powerpc-ibm-os400)      
  . name [argument ...]                   
  : [ argument ... ]                      
  [ expression ]                          
  alias [-p] [name [=value] ...]          
  break [n]                               
  builtin [utility [argument ...]]        
  cd [directory]                          
  command [-p] command_name [argument ...]
  …

# echoコマンドのヘルプを表示する
> help echo                 
  echo: echo [argument ...] 
```

## ln

ハードリンク、シンボリックリンクを作成

```sh
> ln hoge.txt hoge.ln
> ln -s hoge.txt hoge.sym
> ls -li                                                                       
  total: 20 kilobytes                                                          
  160710 -rw-rw-rw-  2 DANISHI 0                     4 Aug 20 16:50 hoge.ln    
  160633 lrwxrwxrwx  1 DANISHI 0                    20 Aug 20 16:55 hoge.sym -> hoge.txt
  160710 -rw-rw-rw-  2 DANISHI 0                     4 Aug 20 16:50 hoge.txt   
> echo test > hoge.ln                                                         
> cat hoge.txt                                                                
  test                                                                        
> rm hoge.txt                                                                 
> cat hoge.ln                                                                 
  test                                                                        
> cat hoge.sym                                                                
  cat: 001-0023  ファイル  hoge.sym  を開くときにエラーが見つかりました。   このようなパスまたはディレクトリーはない。

## logname

ログインユーザ名を表示

```sh
> logname
  DANISHI
```

## locale

ロケール情報を表示

```sh
> locale                       
  LANG=/QSYS.LIB/JA_5035.LOCALE
  LC_COLLATE=                  
  LC_CTYPE=                    
  LC_MESSAGES=                 
  LC_MONETARY=                 
  LC_NUMERIC=                  
  LC_TIME=                     
  LC_ALL=                              
```

## ls

ディレクトリ内のファイルの一覧を表示する(LiSt file)

```sh
# カレントディレクトリにあるファイルの名前を一覧にして表示
> ls
# /tmpディレクトリにあるファイルを一覧にして詳しい情報とともに表示
> ls -l /tmp
```

## mkdir

ディレクトリを作成する(MaKe DIRectory)

```sh
# カレントディレクトリにhoge.dディレクトリを作成する。
> mkdir hoge.d
```

## pwd

カレントディレクトリを表示する(Print Working Directory)

```sh
> pwd
  /QSYS.LIB/DANILIB.LIB
```

## rm

ファイル・ディレクトリを削除する(ReMove)

```sh
# カレントディレクトリのファイルhoge.txtを削除する。
> rm hoge.txt
# hoge.dディレクトリ配下のファイルを全て削除
> rm -r ./hoge.d/*
```

## rmdir

ディレクトリを削除する(ReMove Directory)
空のディレクトリしか削除できない

```sh
# カレントディレクトリのhoge.dディレクトリを削除する。
> rmdir hoge.d
```

## sleep

指定した秒数シェルを停止する

```sh
# シェルを3秒停止する
> sleep 3
```

## tar

アーカイブファイルを作成・展開する

```sh
# hoge.tarファイルを展開
> tar -xvf hoge.tar
```

## tee

標準入力を標準出力とファイルの両方に出力する

```sh
> echo hello | tee tee.log
  hello                   
> cat tee.log             
  hello                   
```

## tr

標準入力から読み込まれた文字列を変換(translate)したり、削除したりする。

```sh
# 指定文字を置換
> echo abcdebcd | tr 'bcd' 'xyz'	
  axyzexyz                      	

# 指定文字を削除
> echo abcdebcd | tr -d 'bc'	
  aded                      	

# ブランクを削除
> echo 'a  b  c    ' | tr -d ' '	
  abc                           	
```

## time

指定したコマンドの実行時間を表示する

```sh
> time sleep 3        
                      
  real     0m3.030112s
  user     0m3.030112s
  sys      0m0.000000s
```

## touch

ファイルの更新時間やアクセス時間を変更する
空ファイルの作成にも使える

```sh
# 空のhoge.txtファイルを作成
> touch hoge.txt
```

## type

引数に指定したコマンドの種類を調べる

```sh
> type pwd                 
  pwd はシェル組み込みです 

> type tar                 
  tar は /usr/bin/tar です 
```

## uncompress

compressで圧縮したファイルを解凍する

```sh
# hoge.tar.zを解凍してhoge.tarを作成。hoge.tar.zは削除される
> uncompress hoge.tar.z
# hoge.tar.zを圧縮してhoge.tarを作成。hoge.tar.zは削除されない
> uncompress -c hoge.tar.z > hoge.tar
```

## unset

変数及び関数の設定を解除する

```sh
> HOGE=FUGA
> echo $HOGE
  FUGA
> unset HOGE
> echo $HOGE
```

## wc

文字数や単語数をカウントする(Word Count)

```sh
> wc hoge.txt
```

## whence

コマンドの実体を表示

```sh
> whence ls
  /usr/bin/ls
> whence lsl
  alias lsl=ls -l
```

# QShellスクリプト

予めコマンドをテキストに保存しておくことで、一連のコマンドをスクリプトとして実行できる。

## スクリプトの実行

```sh
> ./hoge.sh
```

## パラメータを受け取る

```sh
> cat param.sh                     
  # param.sh                       
  echo $0 # スクリプトのファイル名 
  echo $1 # 第１引数               
  echo $2 # 第２引数               
  echo $# # 引数の数               
  exit 0

> ./param.sh p1 p2 p3 
  ./param.sh          
  p1                  
  p2                  
  3                  
```

## 条件分岐

### caseコマンド

多分岐処理を行う

```sh
> cat case.sh                      
  # case.sh                        
  case "$1" in                      
     "red" )   echo " 赤 " ;;           
     "blue" )  echo " 青 " ;;           
     "green" ) echo " 緑 " ;;           
     * )       echo " どれでもない " ;; 
  esac                             
                                   
  exit 0                           

> ./case.sh blue 
  青            

> ./case.sh black
  どれでもない  
```

## 入力

### readコマンド

標準入力・ファイルからデータを読み込み、引数の変数に格納する

```sh
# 変数を宣言し、標準入力から入力
> read DATA     
> Hello Qshell! 

> echo $DATA    
  Hello Qshell! 

# ファイルの内容を変数にセット
> cat test.txt        
  abcde               
               
> read TEXT < test.txt
               
> echo $TEXT          
  abcde               

# 対話型シェルスクリプト
> cat read.sh            
  # read.sh              
  echo What you are name?
  read name              
  echo Hello $name!      
  $                      

> ./read.sh          
  What you are name? 
> Danishi            
  Hello Danishi!  
```

## 関数

```sh
> cat function.sh   
  # function.sh     
  function func1(){ 
      echo 'func1()'
 }                        
 function func2(){        
     echo "func2():$1, $2"
 }                        
 function func3(){        
     return 99            
 }                        
                          
 func1                    
 func2 10 AAA             
 func3                    
 echo "func3():$?"        
 exit 0                   

> function.sh    
  func1()        
  func2():10, AAA
  func3():99     
```

# その他情報

* QShell関連のオブジェクトはライブラリQSHELLにある。
* QShellは物理・論理ファイルをディレクトリとして扱う。  
また、物理ソースファイルのメンバーはストリームファイルのように読み書き可能。
* splitでセーブファイルを分割して転送し、転送先でcatを使い再度1つのファイルにまとめることができる。
* .(ドット)で始まるファイル・ディレクトリは隠しファイルとなり、WRKLNKや-Aオプションなしのlsコマンドでは見えなくなる。
* QShellにはviやEmacsのような、シェルから起動できるエディターが存在しないため、
ストリームファイルの編集にはCLコマンドである、EDTFコマンドを使わなくてはならない、
が、ぶっちゃけ別のOS上で編集したファイルをIFSに置いたほうが早いと思う。
* bashなどで使えるホームディレクトリを表す特殊記号~(チルダ)は、QShellでは使えない(てか打てない)。
* オプションに--helpを指定すればコマンドのヘルプを見ることができる。
* QShell及びPASEを使用するにはCCSIDを次の値に設定する  
`CHGJOB CCSID(5035)`