ゆるふわシェル問題 その3
全部で8問
そんなに難しくないはず
だいたい1~3コマンドで解ける
使う技術
問題
Q1 中身0byteのファイルaを作成してください
a1.shtouch a
: > a
echo -n "" > a
問題の意図
ダミーファイルが欲しくなるときはそれなりにあるので
空ファイル作る方法はいくつかあるけれど echo > a
ではだめ
改行文字も含まれてしまう
解説
touch
もとはファイルのタイムスタンプを更新するコマンドだけど空ファイルを作るのにも使える
:
は何もしないコマンドで、その出力をファイルに書き出している
echo -n
は改行なしで出力する
Q2 以下のテキストファイルaの中の文字列をすべて小文字に変換して上書きしてください
q2.shcat << EOS | tee a
HELLO WORLD
SUSHI
FooBar
EOS
a2.shcat a | tr '[:upper:]' '[:lower:]' > b
mv b a
問題の意図
小文字大文字変換の方法を知る
sed
だとめんどくさい
解説
tr
は処理するデータを標準入力からしか受け付けないので一旦 cat
した結果をパイプで渡す
tr
には置換のパターンがいくつか用意されているのでそれを使う
この例だと大文字を小文字に変換する
いきなりリダイレクトでファイルaを上書きするとファイルの中身が消える
一旦別ファイルに吐き出してから mv
で移動するところまでやって正解
Q3 1 ÷ 3 と -1 ÷ 3 を計算して小数点以下6桁まで出力してください
期待値は以下の通りです
a3.sh # bc の例
echo 'scale=6; 1/3' | bc | sed -E 's/^(-)?\./\10./'
echo 'scale=6; -1/3' | bc | sed -E 's/^(-)?\./\10./'
# awkの例
awk 'BEGIN{ print 1/3; print -1/3 }'
問題の意図
bashの算術演算式だと小数点以下の計算や出力ができないのでやり方を把握する
解説
bc
を使う場合は scale
で小数点以下の桁数を指定する
整数部0が消えるのがトラップ
0を付け足す正規表現を書く
^(-)?\.
^
行頭
(-)?
-
が1つあってもなくても良い
\.
.
文字 ( .
は正規表現で使用する特殊な文字なのでエスケープが必要
\10.
\1
前述の正規表現でマッチした部分をグルーピングした結果を参照する
0.
普通の文字としての 0.
awk
なら普通にそのまま計算すればよい
Q4 以下の複数のディレクトリ配下でそれぞれmakeしてください
a4.shmkdir prog_{1,2,3}
echo $'build:\n\techo build 1' > prog_1/Makefile
echo $'build:\n\techo build 2' > prog_2/Makefile
echo $'build:\n\techo build 3' > prog_3/Makefile
find prog_*
a4.shfor d in prog_*; do
(cd $d && make)
done
問題の意図
スクリプトとかで、一旦ディレクトリを移動して戻る処理をどう書くかを考える
こういうふうに書くと失敗する
shfor d in prog_*; do
cd $d
make
done
一旦ディレクトリを移動した先から更に移動しようとするのでダメ
ありがちなミス
解説
サブシェル内部は別のシェルプロセス
別シェルプロセス内でchange directoryしても親プロセスには影響しない
ループ内だけサブシェルにすることで、次のループに影響を残さない
Q5 1コマンドで1 3 5 7 9 ... 20を出力してください
a5.shawk 'BEGIN{ for(i=0; i<20; i+=2) { print i+1 }; print 20 }'
seq 1 2 20 # NG
echo {1..20..2} 20 # egplさんの解答
問題の意図
seq
の使い方 (フェイク)
解説
seq
は等差数列を生成する際の交差の値を指定できる
この場合は初項1から20までを交差2で生成する
が、最後の数値20は出力されないのでNG
結局 awk
で解く
egpl
さんの解答のほうがスマートで良い
Q6 以下のテキストファイルaの中身を文字化けしないように画面に出力してください
q6.shecho 'jvWOaQo=' | base64 -d > a
a6.sh# 僕の用意した答え
nkf --guess a
cat a | iconv -f SJIS -t UTF-8
# タイムラインに流れてきた答え
nkf -w a
問題の意図
文字コードを変換する処理
解説
iconv
元はSJISの「寿司」をBase64エンコードしたもの
問題を出題するときにパット見何が書かれてるかわからなくしたくてBase64にした
nkf --guess
で文字コードを調べられる
SJISだとわかったので iconv
でSJISをUTF8に変換する
nkf -w
タイムラインに流れてきて知ったけれど -w
でも良い
Q7 /etc/passwdの各列の桁数をそろえて人間が読みやすい形で出力してください。不足の列がずれないように配慮してください
a7.shcat /etc/passwd | sed "s/::/: :/g" | column -s : -t | textimg -s #シェル芸
問題の意図
column
コマンド使うと見やすくなるよ
解説
column -t
でいい感じに桁を揃えて出力できる
column -s :
で区切り文字を指定できる
ただし、これだけだと /etc/passwd
には空の列も存在するので、一部の列がずれる
sed
の部分で空白文字を挟むことで解決
Q8 カレントディレクトリの末尾2階層分の文字列をとりだして結合して出力してください
q8.shecho "例: /work/proj1/app から proj1app という文字列を取り出す"
mkdir -p /work/proj1/app
cd $_
a8.shpwd | tr / \\n | tail -n 2 | tr -d \\n
問題の意図
この前友人に相談されたことで、それをそのまま問題にしてみた
解き方色々ありそうでどうなるかなぁと
解説
pwd
でカレントディレクトリを出力
tr
でディレクトリの区切り文字を改行文字に置換
改行されたディレクトリ名の末尾2行を取得
改行文字を削除することで結合
以上
余談
と思ったけれどその1もその2もコマンド知ってないと難しそうなのあるな
個人的にはQ7が一番難しいかな、と