私は本当にこのチュートリアルを書きたくありませんが、既存のBashチュートリアルがあまりにもひどいので、仕方がありません。本、ウェブサイト、YouTubeを見ましたが、どれもひどいです。基本から始めていません。無駄なものがたくさん含まれています。そして、コアコンセプトを説明していません。だから、私はこのリアクショナリープログラミングを学ぶBashレッスンのためにこれを書くしかありません。
Bashはシェルの一つで、私が好むものです。MacとWindowsに焦点を当てます。Linuxは持っていませんし、嫌いなので、話しません。BashのほとんどはMacとWindowsで同じですが、異なる部分については両方を説明します。
Bashへのアクセス方法はオペレーティングシステムによって異なります。Macの場合、"Applications > Utilities > Terminal.app"にあるMacターミナルを通じてBashにアクセスします。デフォルトのシェルをBashに設定してください。Windowsの場合はMSYS2をインストールします。デフォルトのターミナルはあまり良くないので、Windowsターミナルを使用することをお勧めします。
MacでBashを起動すると、次のように表示されます:
Last login: Thu Jan 4 23:25:35 on ttys004
The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
~ $
Windows - MSYS2では、次のように表示されます:
~ $
$
のある行はコマンドプロンプトです。カーソルはその末尾にあり、入力するとテキストがそこに表示されます。$
の前に異なるテキストが表示されることがありますが、それは問題ありません。ただし、行は$
で終わる必要があります。そうでない場合は、何かが間違っています。
「qqq」と入力してください。「何かを入力」と言った場合、最後にリターン/エンターを入力する必要があります。リターン/エンターを入力したときにのみ、Bashは入力した内容を処理します。次のように表示されるはずです:
~ $ qqq
-bash: qqq: command not found
~ $
Bashは「qqq」が何を意味するのか分からず、そのように表示します。次に、以下を試してください... $
の後にあるものを入力し、Bashが示すように応答するはずです。
~ $ echo hi
hi
~ $ echo how are you
how are you
~ $ echo bye
bye
echo
コマンドは、後に続くものをエコーします。次に、キーボードの上矢印を押してください。これにより、カーソルの位置に前のコマンドが表示されます。もう一度上矢印を押すと、その前のコマンドが表示されます。下矢印、左矢印、右矢印を試してください。これを使用してコマンド履歴をナビゲートできます。削除キーも行の編集に使用できます。そしてもちろん、入力できます。リターン/エンターを押すと、Bashは編集されたコマンドを取得して処理します。
echo how are you
を入力すると、echo
はコマンドです。このコマンドには3つの引数があります:how
、are
、you
。コマンドと引数はスペースで区切られます。スペースの数は関係ありませんので:
~ $ echo how are you
how are you
echo
は引数を1つのスペースで区切って返します。
~ $ echo one; echo two
one
two
1行に複数のコマンドを;
で区切って配置できます。
入力してください:
~ $ man echo
次のようなものが表示されるはずです:
ECHO(1) BSD General Commands Manual ECHO(1)
NAME
echo -- write arguments to the standard output
SYNOPSIS
echo [-n] [string ...]
DESCRIPTION
The echo utility writes any specified operands, separated by single blank
(` ') characters and followed by a newline (`\n') character, to the stan-
dard output.
The following option is available:
-n Do not print the trailing newline character. This may also be
achieved by appending `\c' to the end of the string, as is done by
iBCS2 compatible systems. Note that this option as well as the
effect of `\c' are implementation-defined in IEEE Std 1003.1-2001
(``POSIX.1'') as amended by Cor. 1-2002. Applications aiming for
maximum portability are strongly encouraged to use printf(1) to
suppress the newline character.
:
しかし、Windowsの場合、man
がインストールされていないかもしれません。その場合は、次を実行してください:
~ $ pacman -S man-db
ここで説明されているようにman
をインストールし、再度man echo
を試してください。
man
コマンドはコマンドのドキュメントを表示します。残念ながら、キーを覚えることに基づいた愚かなユーザーインターフェースを持っているので、必要なキーだけを教えます。下矢印と上矢印は1行ずつ下と上に移動します。スペースキーは1ページ下に移動します。そして最も重要なのは、「q」を入力すると終了し、Bashに戻ります。これを覚えておく必要があります。
次にman man
を入力してみてください。表示されるすべての情報が必要なわけではありませんが、複雑なmanページがどのように見えるかを確認できます。他のコマンドのドキュメントを取得するためにman
を使用できます。
Mac FinderまたはWindowsファイルエクスプローラーに精通しているはずで、これからディレクトリ(「フォルダ」とも呼ばれる)がツリー状に整理されていることを知っているはずです。
Macの場合:
~ $ pwd
/Users/fschmidt
~ $ open .
~ $
Windowsの場合:
~ $ pwd
/home/fschmidt
~ $ explorer .
~ $
Bashを使用しているときは、常にあるディレクトリにいます。これをカレントディレクトリまたは作業ディレクトリと呼びます。pwd
はこのディレクトリへのフルパスを表示します。詳細についてはman pwd
を参照してください。open .
はカレントディレクトリのMac Finderを開き、explorer .
はカレントディレクトリのWindowsファイルエクスプローラーを開くはずです。
Macで続けます:
~ $ mkdir learn
~ $ cd learn
~/learn $ pwd
/Users/fschmidt/learn
mkdir
はカレントディレクトリにディレクトリを作成します。Mac FinderまたはWindowsファイルエクスプローラーで作成されたディレクトリを確認できるはずです。cd
は「ディレクトリを変更する」の略です。これによりカレントディレクトリが変更されます。cd
は組み込みコマンド(Bashに組み込まれている)であり、man
は組み込みコマンドには役立たないため、man cd
の代わりにhelp cd
を試してください。続けます...
~/learn $ pwd
/Users/fschmidt/learn
~/learn $ ls
~/learn $ touch file1
~/learn $ ls
file1
~/learn $ touch file2
~/learn $ touch file3
~/learn $ ls
file1 file2 file3
~/learn $ mkdir dir1
~/learn $ ls
dir1 file1 file2 file3
~/learn $ ls -F
dir1/ file1 file2 file3
~/learn $ ls -a
. .. dir1 file1 file2 file3
~/learn $ ls -a -F
./ ../ dir1/ file1 file2 file3
~/learn $ ls -aF
./ ../ dir1/ file1 file2 file3
ls
はファイルをリストし、touch
は空のファイルを作成します。-
で始まる引数はオプションです。使用したオプションの詳細についてはman ls
を参照してください。-F
はディレクトリに「/」を追加し、-a
は通常隠されている「.」で始まるファイルを表示します。オプションは組み合わせることができます。
~/learn $ ls file1
file1
~/learn $ ls qqq
ls: qqq: No such file or directory
~/learn $ ls file1 qqq file2
ls: qqq: No such file or directory
file1 file2
~/learn $ ls dir1
~/learn $ touch dir1/d1file
~/learn $ ls dir1
d1file
~/learn $ ls -d dir1
dir1
~/learn $ ls file1 file2 dir1
file1 file2
dir1:
d1file
~/learn $ ls -d file1 file2 dir1
dir1 file1 file2
~/learn $ ls -dF file1 file2 dir1
dir1/ file1 file2
ファイル引数なしで、ls
はカレントディレクトリのファイルをリストします。ファイル引数がある場合、それらのファイルが存在する場合にリストします。ファイルがディレクトリの場合、-d
オプションが使用されない限り、ディレクトリ内の内容をリストします。
~/learn $ ls
dir1 file1 file2 file3
~/learn $ ls .
dir1 file1 file2 file3
~/learn $ ls -d .
.
~/learn $ ls -dF .
./
~/learn $ ls ./file1
./file1
~/learn $ ls dir1
d1file
~/learn $ ls ./dir1
d1file
~/learn $ pwd
/Users/fschmidt/learn
~/learn $ cd .
~/learn $ pwd
/Users/fschmidt/learn
.
はカレントディレクトリです。
~/learn $ pwd
/Users/fschmidt/learn
~/learn $ cd dir1
~/learn/dir1 $ pwd
/Users/fschmidt/learn/dir1
~/learn/dir1 $ ls .
d1file
~/learn/dir1 $ ls ..
dir1 file1 file2 file3
~/learn/dir1 $ cd ..
~/learn $ pwd
/Users/fschmidt/learn
~/learn $ cd dir1
~/learn/dir1 $ pwd
/Users/fschmidt/learn/dir1
~/learn/dir1 $ cd ../..
~ $ pwd
/Users/fschmidt
~ $ cd learn
~/learn $ pwd
/Users/fschmidt/learn
..
は親ディレクトリです。
~/learn $ echo *
dir1 file1 file2 file3
~/learn $ echo d*
dir1
~/learn $ echo f*
file1 file2 file3
~/learn $ echo *1
dir1 file1
~/learn $ echo dir1/*
dir1/d1file
~/learn $ echo */*
dir1/d1file
~/learn $ echo qqq*
qqq*
*
はファイルのワイルドカードマッチングを行います。重要なのは、Bashがワイルドカードマッチングを行い、その結果の引数をコマンドに渡すことです。echo
は一致がない限り「*」を見ません。
~/learn $ ls *
file1 file2 file3
dir1:
d1file
~/learn $ ls -dF *
dir1/ file1 file2 file3
~/learn $ ls -dF d*
dir1/
~/learn $ ls -dF f*
file1 file2 file3
~/learn $ ls -dF *1
dir1/ file1
~/learn $ ls dir1/*
dir1/d1file
~/learn $ ls */*
dir1/d1file
~/learn $ ls -dF qqq*
ls: qqq*: No such file or directory
自明であるべきです。
~/learn $ pwd
/Users/fschmidt/learn
~/learn $ cd ~
~ $ pwd
/Users/fschmidt
~ $ cd learn/dir1
~/learn/dir1 $ pwd
/Users/fschmidt/learn/dir1
~/learn/dir1 $ cd
~ $ pwd
/Users/fschmidt
~ $ cd ~/learn
~/learn $ pwd
/Users/fschmidt/learn
~/learn $ echo ~
/Users/fschmidt
~/learn $ echo .
.
~/learn $ echo ..
..
~
はホームディレクトリを意味します。引数なしのcd
はcd ~
と同じです。~
はBashによってホームディレクトリに展開されます。
~/learn $ ls -ltF
total 0
drwxr-xr-x 3 fschmidt staff 96 Jan 5 02:33 dir1/
-rw-r--r-- 1 fschmidt staff 0 Jan 5 02:21 file3
-rw-r--r-- 1 fschmidt staff 0 Jan 5 02:21 file2
-rw-r--r-- 1 fschmidt staff 0 Jan 5 02:21 file1
-l
はこの醜い技術的な形式を提供します。ファイルが最後に変更された日付を取得します。日付の前にはファイルサイズがあります。-t
は日付で降順にソートします。
最後にオートコンプリートについて説明します。echo d
と入力し、リターン/エンターを押さずにタブキーを押します。これによりecho dir1/
に自動補完されます。もう一度タブを押すとecho dir1/d1file
に自動補完されます。ファイルやディレクトリを入力中にタブを押すと、Bashが一致するファイル名を使用して自動補完を試みます。echo f
を入力してタブを押すとecho file
になります。次にどれを選ぶべきか分かりません。もう一度タブを押すとビープ音が鳴ります。そしてもう一度タブを押すと、次のようにオプションが表示されます:
~/learn $ echo file
file1 file2 file3
~/learn $ echo file
一般的に、ファイル名を入力中にいつでもタブを押してみてください。オートコンプリートは多くの入力を節約します。
~/learn $ ls -F
dir1/ file1 file2 file3
~/learn $ cp file1 copied
~/learn $ ls -F
copied dir1/ file1 file2 file3
~/learn $ mv copied moved
~/learn $ ls -F
dir1/ file1 file2 file3 moved
~/learn $ rm moved
~/learn $ ls -F
dir1/ file1 file2 file3
cp
はファイルやディレクトリをコピーします。mv
はファイルやディレクトリを移動します。rm
はファイルやディレクトリを削除します。これらのコマンドの詳細についてはman
ページを参照してください。
~/learn $ ls -F
dir1/ file1 file2 file3
~/learn $ mkdir dir2
~/learn $ touch dir2/d2file
~/learn $ ls -F
dir1/ dir2/ file1 file2 file3
~/learn $ ls dir2
d2file
~/learn $ rm dir2
rm: dir2: is a directory
~/learn $ rm -d dir2
rm: dir2: Directory not empty
~/learn $ rm dir2/d2file
~/learn $ rm -d dir2
~/learn $ ls -F
dir1/ file1 file2 file3
~/learn $ ls -F
dir1/ file1 file2 file3
~/learn $ mkdir dir2
~/learn $ touch dir2/d2file
~/learn $ ls -F
dir1/ dir2/ file1 file2 file3
~/learn $ rm -r dir2
~/learn $ ls -F
dir1/ file1 file2 file3
~/learn $ ls -F
dir1/ file1 file2 file3
~/learn $ cp dir1 dir2
cp: dir1 is a directory (not copied).
~/learn $ cp -r dir1 dir2
~/learn $ ls -F
dir1/ dir2/ file1 file2 file3
~/learn $ ls dir2
d1file
~/learn $ cp f* dir2
~/learn $ ls dir2
d1file file1 file2 file3
~/learn $ rm -r dir2
~/learn $ ls -F
dir1/ file1 file2 file3
~/learn $ ls -F
dir1/ file1 file2 file3
~/learn $ mkdir dir2
~/learn $ cp -r dir1 dir2
~/learn $ ls -F dir2
dir1/
~/learn $ ls -F dir2/dir1
d1file
~/learn $ rm -r dir2
~/learn $ ls -F
dir1/ file1 file2 file3
これをすべて説明することもできますが、しません。man
を使用してコマンドとそのオプションを理解し、それらを試してみてください。完全に理解するまで続けないでください。
~/learn $ echo a b
a b
~/learn $ echo "a b"
a b
~/learn $ echo 'a b'
a b
~/learn $ echo "a b" c
a b c
Bashは引用符内のテキストを1つの引数として扱います。したがって、echo a b
では、echo
には2つの引数があります:「a」と「b」。echo "a b"
では、echo
には1つの引数があります:「a b」。echo 'a b'
では、echo
には1つの引数があります:「a b」。echo "a b" c
では、echo
には2つの引数があります:「a b」と「c」。
~/learn $ echo a\ \ \ b
a b
引用符の外では、\
は区切り文字として扱われず、引数の一部としてスペース文字として扱われます。
~/learn $ echo $X
~/learn $ X="some text"
~/learn $ echo $X
some text
~/learn $ echo "X is: $X"
X is: some text
~/learn $ echo 'X is: $X'
X is: $X
~/learn $ X="$X and more"
~/learn $ echo $X
some text and more
ここでX
は変数です。$X
でその値を取得します。これはダブルクォート内でも機能しますが、シングルクォート内では機能しません。
Bashで使用される特別な変数である環境変数があります。
~/learn $ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/fschmidt/Dropbox/bin:/Users/fschmidt/hg/luan/scripts:/usr/local/opt/postgresql@9.5/bin
~/learn $ which ls
/bin/ls
~/learn $ cd /bin
/bin $ pwd
/bin
/bin $ ls
[ dd launchctl pwd test
bash df link rm unlink
cat echo ln rmdir wait4path
chmod ed ls sh zsh
cp expr mkdir sleep
csh hostname mv stty
dash kill pax sync
date ksh ps tcsh
/bin $ ls -F
[* dd* launchctl* pwd* test*
bash* df* link* rm* unlink*
cat* echo* ln* rmdir* wait4path*
chmod* ed* ls* sh* zsh*
cp* expr* mkdir* sleep*
csh* hostname* mv* stty*
dash* kill* pax* sync*
date* ksh* ps* tcsh*
/bin $ cd ~/learn
~/learn $
PATH
はBashがコマンドを検索するディレクトリのリストを:
で区切って含む環境変数です。which
コマンドはコマンドへのフルパスを表示します。ls -F
は実行可能ファイルに*
を追加します。
~/learn $ subl file1
-bash: subl: command not found
~/learn $ "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" file1
~/learn $ PATH="$PATH:/Applications/Sublime Text.app/Contents/SharedSupport/bin"
~/learn $ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/fschmidt/Dropbox/bin:/Users/fschmidt/hg/luan/scripts:/usr/local/opt/postgresql@9.5/bin:/Applications/Sublime Text.app/Contents/SharedSupport/bin
~/learn $ subl file1
~/learn $
ここでは、最初にフルパスを使用してSublime Textでファイルfile1
を編集し、次にディレクトリをPATH
に追加してBashがsubl
を見つけられるようにします。
WindowsではMicrosoft Wordを持っています。Windowsコマンドプロンプト(Bashではなく)から:
C:\Users\fschmidt>winword
C:\Users\fschmidt>where winword
C:\Program Files\Microsoft Office\root\Office16\WINWORD.EXE
winword
はMicrosoft Wordを実行します。コマンドプロンプトのwhere
コマンドはBashのwhich
コマンドのようなものです。では、MSYS2で:
~ $ winword
bash: winword: command not found
~ $ echo $PATH
/usr/local/bin:/usr/bin:/bin:/opt/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/c/Program Files/TortoiseHg:/c/Program Files/Java/jdk1.8.0_202/bin
~ $ PATH="$PATH:/c/Program Files/Microsoft Office/root/Office16"
~ $ echo $PATH
/usr/local/bin:/usr/bin:/bin:/opt/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/c/Program Files/TortoiseHg:/c/Program Files/Java/jdk1.8.0_202/bin:/c/Program Files/Microsoft Office/root/Office16
~ $ winword
~ $
Macに戻ると、Finderの「アプリケーション」にあるアプリケーションをコマンドとしてではなくアプリケーションとして実行する別の方法があります。
~/learn $ open -a 'Sublime Text' file1
もう1つの便利な環境変数はPS1
で、コマンドプロンプトを制御します。私はすでにこれを設定していますが、していない場合:
Franklins-MacBook-Pro:learn fschmidt$ echo $PS1
\h:\W \u\$
Franklins-MacBook-Pro:learn fschmidt$ PS1="\w $ "
~/learn $ echo $PS1
\w $
~/learn $
「bash PS1」をGoogleで検索してください。
~/learn $ cd
~ $ ls .bash_profile
.bash_profile
もし.bash_profile
が見つからない場合は、touch .bash_profile
を実行して作成してください。このファイルには、Bashが起動したときに実行されるBashコマンドが含まれています。すでにこのファイルがある場合、#
で始まるコメントが含まれている可能性があります。コメントは無視されます:
~ $ # コメント行、何もしません
~ $ echo whatever # 行末コメント
whatever
~ $
Macで.bash_profile
を編集するには、次を実行できます:
~ $ open -a 'Sublime Text' .bash_profile
Windowsで.bash_profile
を編集するには、次を実行できます:
~ $ notepad .bash_profile
次の行を.bash_profile
に追加してみてください:
echo hello there
新しいBashターミナルを開くと、「hello there」が表示されるはずです。.bash_profile
は、新しいBashターミナルを開くことでBashが開始されたときに実行されます。
私はPS1
とPATH
を.bash_profile
に設定して、望むコマンドプロンプトとアクセスしたいコマンドを持つようにしています。Sublime Textコマンドsubl
をPATH
で利用可能にすることをお勧めします。
~/learn $ find .
.
./file3
./file2
./file1
./dir1
./dir1/d1file
~/learn $ find . -name 'file*'
./file3
./file2
./file1
~/learn $ find . -name '*file'
./dir1/d1file
~/learn $ find . -name 'd*'
./dir1
./dir1/d1file
~/learn $ find . -name '*1' -or -name '*2'
./file2
./file1
./dir1
find
はディレクトリツリー内のファイルを再帰的に検索します。この場合、*
のワイルドカードマッチングはBashによって行われているのではなく、find
によって行われています。find
にはファイルを検索し、それに対してアクションを実行するための多くのオプションがあります。man find
を参照してください。
~/learn $ echo 'this is a test' >test.txt
~/learn $ ls -F
dir1/ file1 file2 file3 test.txt
~/learn $ cat test.txt
this is a test
~/learn $ echo 'this is another test' >test.txt
~/learn $ cat test.txt
this is another test
~/learn $ echo 'another line' >>test.txt
~/learn $ cat test.txt
this is another test
another line
~/learn $ cat <test.txt
this is another test
another line
~/learn $ cat <<End >test.txt
> I am typing this
> and this
> End
~/learn $ cat test.txt
I am typing this
and this
~/learn $ (echo one; echo two) >test.txt
~/learn $ cat test.txt
one
two
すべてのプログラムには標準入力、標準出力、標準エラーがあります。プログラムは通常の出力を標準出力に書き込み、エラーメッセージを標準エラーに書き込みます。デフォルトでは、標準入力はターミナルから来て、標準出力と標準エラーはターミナルに行きますが、これを変更できます。>file
は標準出力をfile
に送ります。>>file
は標準出力をfile
に追加します。<file
は標準入力をfile
から読み込みます。<<whatever
はwhatever
だけの行が来るまで続くテキストから標準入力を読み込みます。コマンドは(
と)
の間で組み合わせることができます。cat
の動作を理解するためにman cat
を必ず行ってください。
~/learn $ ls >ls.txt
~/learn $ cat ls.txt
dir1
file1
file2
file3
ls.txt
test.txt
~/learn $ ls -d f* q* >ls.txt
ls: q*: No such file or directory
~/learn $ cat ls.txt
file1
file2
file3
~/learn $ ls -d f* q* 2>ls.txt
file1 file2 file3
~/learn $ cat ls.txt
ls: q*: No such file or directory
~/learn $ ls -d f* q* | tee ls.txt
ls: q*: No such file or directory
file1
file2
file3
~/learn $ cat ls.txt
file1
file2
file3
~/learn $ ls -d f* q* 2>&1 | tee ls.txt
ls: q*: No such file or directory
file1
file2
file3
~/learn $ cat ls.txt
ls: q*: No such file or directory
file1
file2
file3
2>file
は標準エラーをfile
に送ります。|
は前のコマンドの標準出力を次のコマンドの標準入力に送ります。2>&1
は標準エラーを標準出力に送ります。tee file
は標準入力を読み取り、それを標準出力とfile
の両方に書き込みます。
~/learn $ find . -type f | wc -l
6
learn
には6つのファイルがあります。これがどのように機能するかを理解するためにman
を使用してください。
~/learn $ sleep 3
~/learn $ sleep 30
^C
~/learn $
sleep 3
は3秒間スリープします。つまり、3秒間何もしません。このコマンドが終了するのを3秒待ちました。次にsleep 30
を実行しましたが、30秒間スリープするはずでしたが、我慢できずにcontrol+cを押してプログラムを中断し、抜け出しました。コマンドが終了するのを待っているときに行き詰まった場合は、control+cを試してみてください。
~/learn $ wc
I am typing this
and this
now I will end my input with control+d
3 14 65
~/learn $ wc
this time I will use control+c to break out
^C
~/learn $
Control+dは入力の終了を意味します。
~/learn $ echo I am in $(pwd)
I am in /Users/fschmidt/learn
~/learn $ echo this directory contains: $(ls)
this directory contains: dir1 file1 file2 file3 ls.txt test.txt
~/learn $ echo this directory contains $(ls | wc -l) files
this directory contains 6 files
cmd $(commands)
はcommands
の出力をcmd
の引数テキストとして使用します。
~/learn $ cat $(find . -type f) | wc -c
86
learn
のファイルには合計86バイトが含まれています。これがどのように機能するかを理解するためにman
を使用してください。
~/learn $ (sleep 5; echo done) &
[1] 10080
~/learn $ echo waiting
waiting
~/learn $ done
[1]+ Done ( sleep 5; echo done )
~/learn $
通常、Bashはコマンドが完了するのを待ってからコマンドプロンプトを表示し、入力を許可します。しかし、コマンドラインの末尾に&
を付けると、bashは待たずにコマンドを別のプロセスで実行します。上記の~/learn $ echo waiting
では、echo waiting
を入力しました。しかし、~/learn $ done
では、done
を入力しませんでした。代わりに、これは5秒後にecho done
によって生成されました。[1] 10080
はプロセスが開始されたことを示し、[1]+ Done ( sleep 5; echo done )
はプロセスが終了したことを示します。
これは、コマンドが終了するのを待ちたくない場合に便利です。Windowsでこれを考えてみてください:
~ $ notepad
ここでは、Bashがこのコマンドの終了を待っているため、Notepadを終了するまでコマンドプロンプトを再度取得できません。代わりに次を実行します:
~ $ notepad &
[1] 2010
~ $
これでNotepadが実行され、Bashを続けて使用できます。
test.sh
というファイルを作成し、次の内容を含めます:
echo this is a shell script
次にBashから:
~/learn $ cat test.sh
echo this is a shell script
~/learn $ ./test.sh
-bash: ./test.sh: Permission denied
~/learn $ ls -F test.sh
test.sh
~/learn $ chmod +x test.sh
~/learn $ ls -F test.sh
test.sh*
~/learn $ ./test.sh
this is a shell script
~/learn $
chmod +x file
はfile
を実行可能にして実行できるようにします。次にtest.sh
を編集します
~/learn $ # edit test.sh
~/learn $ cat test.sh
nonsense
echo this is a shell script
~/learn $ ./test.sh
./test.sh: line 1: nonsense: command not found
this is a shell script
~/learn $ # edit test.sh
~/learn $ cat test.sh
set -e
nonsense
echo this is a shell script
~/learn $ ./test.sh
./test.sh: line 2: nonsense: command not found
~/learn $
デフォルトでは、スクリプトはエラー後も実行を続けます。長いスクリプトでは、エラー後にスクリプトを終了させたいです。set -e
はこれを行います。help set
を参照してください。
~/learn $ X=some
~/learn $ echo $X
some
~/learn $ echo $Xthing
~/learn $ echo ${X}thing
something
~/learn $ # edit test.sh
~/learn $ cat test.sh
echo "\$* = $*"
echo "\$# = $#"
echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"
echo "\$4 = $4"
echo "\$14 = $14"
echo "\${14} = ${14}"
echo "\$@ = $@"
./count.sh "$*"
./count.sh "$@"
~/learn $ ./test.sh a b "c d"
$* = a b c d
$# = 3
$0 = ./test.sh
$1 = a
$2 = b
$3 = c d
$4 =
$14 = a4
${14} =
$@ = a b c d
1
3
~/learn $ cat count.sh
echo $#
~/learn $
Bashスクリプトには特別に定義された変数があります。$*
と$@
の違いは微妙で、通常は$*
を使用します。$*
はすべての引数を1つの文字列として返し、$@
は引数を個別に返しますが、この違いはほとんど影響を与えません。
~/learn $ X=value
~/learn $ echo $X
value
~/learn $ # edit test.sh
~/learn $ cat test.sh
echo "\$X = $X"
~/learn $ ./test.sh
$X =
~/learn $ export X
~/learn $ ./test.sh
$X = value
変数は現在のシェルで定義されます。シェルスクリプトは独自のシェルで実行されます。したがって、デフォルトでは、ターミナル/親シェルで定義された変数を参照しません。export var
はvar
を子プロセスで利用可能にします。つまり、シェルスクリプトで利用可能にします。.bash_profile
でexport PATH
を行うことをお勧めします。これにより、PATHがスクリプトで利用可能になります。
~/learn $ X=terminal
~/learn $ echo $X
terminal
~/learn $ # edit test.sh
~/learn $ cat test.sh
X=script
export X
~/learn $ ./test.sh
~/learn $ echo $X
terminal
~/learn $ . test.sh
~/learn $ echo $X
script
変数を親から子にエクスポートできますが、子から親にはできません。. script
はファイルscript
のテキストを現在のシェルに含めます。この場合、別のシェルで実行されません。これがスクリプトでターミナルシェルに変数を設定する唯一の方法です。
~/learn $ pwd
/Users/fschmidt/learn
~/learn $ # edit test.sh
~/learn $ cat test.sh
cd ~
~/learn $ ./test.sh
~/learn $ pwd
/Users/fschmidt/learn
~/learn $ . test.sh
~ $ pwd
/Users/fschmidt
~ $ cd learn
~/learn $
これは./script
と. script
の違いを示しています。
~/learn $ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/fschmidt/Dropbox/bin:/Users/fschmidt/hg/luan/scripts:/usr/local/opt/postgresql@9.5/bin:/Applications/Sublime Text.app/Contents/SharedSupport/bin
~/learn $ echo ~/Dropbox/bin
/Users/fschmidt/Dropbox/bin
~/learn $ ls -F ~/Dropbox/bin/e
/Users/fschmidt/Dropbox/bin/e*
~/learn $ cat ~/Dropbox/bin/e
open -a 'Sublime Text' $*
~/learn $ e test.sh
~/learn $
役立つスクリプトを書くときは、それらをディレクトリに入れ、そのディレクトリをPATHに追加します。私は~/Dropbox/bin
を使用しており、そこにe
という名前のスクリプトがあります。これにより、コマンドラインからファイルを編集できます。e test.sh
はコマンドラインからtest.sh
を編集できます。
Bashはスクリプトを探すときに、明示的なパスを指定しない限り、PATH内のスクリプトのみを探します。
~/learn $ # edit test.sh
~/learn $ cat test.sh
echo this is a shell script
~/learn $ test.sh
-bash: test.sh: command not found
~/learn $ ./test.sh
this is a shell script
~/learn $
test.sh
を単独で呼び出すと失敗します。これはPATHにないためです。しかし、./test.sh
は明示的なパスであるため機能します。
ここにWord DOCXファイルを解凍するundocx.sh
というより高度なスクリプトがあります。
#!/bin/bash
set -e
if [ $# -ne 1 ]; then
echo "usage: $0 filename"
exit 1
fi
FILE="$1"
NEWDIR=$(basename $FILE .docx)
mkdir $NEWDIR
unzip $FILE -d $NEWDIR
export XMLLINT_INDENT=$'\t'
for file in $(find $NEWDIR -name "*.xml" -o -name "*.rels"); do
mv "$file" temp.xml
xmllint --format temp.xml >"$file"
done
rm temp.xml
Bashは通常の機能をすべて含む完全なプログラミング言語です。私のスクリプトのいくつかのコマンドはman
でよく説明されていますが、いくつかはそうではありません。特にif
とfor
のドキュメントは不十分です。このような場合、ChatGPTに次のように尋ねることをお勧めします:
Bashの「if」文を説明してください。
Bashの「for」文を説明してください。
ChatGPTはBashをよく知っています。ChatGPTに詳細を説明してもらうことを信頼していますが、コアコンセプトを説明することは信頼していません。Googleを試すこともできますが、ChatGPTは現代のプログラマーよりも優れています。
Bashの使用の少なくとも90%は、ターミナルに入力する単純なコマンドです。できるだけBashを使用し、GUIを使用せずに練習してください。システム管理者にならない限り、高度なスクリプトをあまり使用しません。しかし、コアの基本をしっかりと理解していれば、必要に応じて高度なスクリプトを読み書きする方法を理解できるはずです。