システム管理者として、シェルは日常業務の一部です。シェルは、多くの場合、グラフィカルユーザーインターフェイス(GUI)よりも多くのオプションと柔軟性を提供します。毎日繰り返されるタスクは、スクリプトによって簡単に自動化できます。または、タスクを1日の特定の時間に実行するようにスケジュールすることもできます。シェルは、システムと対話するための便利な方法を提供し、より短い時間でより多くのことを実行できるようにします。 Bash、zsh、tcsh、PowerShellなど、さまざまなシェルがあります。
この2部構成のブログ投稿では、作業をスピードアップし、コーヒーを飲む時間を増やすために使用するBashワンライナーのいくつかを共有しています。この最初の投稿では、履歴、最後の引数、ファイルとディレクトリの操作、ファイルの内容の読み取り、およびBash関数について説明します。パート2では、シェル変数、findコマンド、ファイル記述子、およびリモートでの実行操作について説明します。
履歴コマンドを使用する
history
コマンドは便利なものです。 History
特定のシステムで実行したコマンドや、そのコマンドに渡された引数を確認できます。 history
を使用しています 何も覚えなくてもコマンドを再実行できます。
最近のコマンドの記録は、デフォルトで~/.bash_history.
に保存されます。 この場所は、HISTFILEシェル変数を変更することで変更できます。 HISTSIZE(現在のセッションのためにメモリに保存する行)やHISTFILESIZE(履歴ファイルに保持する行数)などの他の変数があります。 history
についてもっと知りたい場合 、man bash
を参照してください 。
次のコマンドを実行するとします。
$> sudo systemctl status sshd
Bashはsshdサービスが実行されていないことを教えてくれるので、次にやりたいのはサービスを開始することです。以前のコマンドでステータスを確認しました。そのコマンドはhistory
に保存されました 、参照できます。実行するだけです:
$> !!:s/status/start/
sudo systemctl start sshd
上記の式の内容は次のとおりです。
- !! -履歴の最後のコマンドを繰り返します
- :s / status /start/-ステータスに置き換えます 開始で
その結果、sshdサービスが開始されます。
次に、次のコマンドを使用して、デフォルトのHISTSIZE値を500から5000に増やします。
$> echo “HISTSIZE=5000” >> ~/.bashrc && source ~/.bashrc
履歴の最後の3つのコマンドを表示したい場合はどうすればよいですか?入力します:
$> history 3
1002 ls
1003 tail audit.log
1004 history 3
tail
を実行します audit.log
で 履歴行番号を参照してください。この場合、1003行目を使用します:
$> !1003
tail audit.log
..
..
別の端末またはブラウザから何かをコピーし、そのコピー(コピーバッファにある)を誤って端末に貼り付けたとします。これらの行は履歴に保存されますが、これは不要なものです。ここで、HISTFILE&&の設定を解除します。 便利です
$> unset HISTFILE && exit
または
$> kill -9 $$
前のコマンドの最後の引数を参照
異なるディレクトリのディレクトリの内容を一覧表示したい場合、ディレクトリ間を頻繁に変更することがあります。前のコマンドの最後の引数を参照するために使用できる優れたトリックがあります。例:
$> pwd
/home/username/
$> ls some/very/long/path/to/some/directory
foo-file bar-file baz-file
上記の例では、/some/very/long/path/to/some/directory
前のコマンドの最後の引数です。
cd
したい場合 (ディレクトリを変更)その場所に、次のように入力します:
$> cd $_
$> pwd
/home/username/some/very/long/path/to/some/directory
次に、ダッシュ文字を使用して、元の場所に戻ります。
$> cd -
$> pwd
/home/username/
ファイルとディレクトリでの作業
ディレクトリ構造を作成し、拡張子が異なる一連のファイルをこれらのディレクトリに移動したいとします。
まず、ディレクトリを一度に作成します:
$> mkdir -v dir_{rpm,txt,zip,pdf}
mkdir: created directory 'dir_rpm'
mkdir: created directory 'dir_txt'
mkdir: created directory 'dir_zip'
mkdir: created directory 'dir_pdf'
次に、ファイル拡張子に基づいてファイルを各ディレクトリに移動します。
$> mv -- *.rpm dir_rpm/
$> mv -- *.pdf dir_pdf/
$> mv -- *.txt dir_txt/
$> mv -- *.zip dir_txt/
二点鎖線の文字--
オプションの終了を意味します。このフラグは、ダッシュで始まるファイルが引数として扱われないようにします。
次に、すべての*.txtファイルを*.logファイルに置き換え/移動したいので、次のように入力します。
$> for f in ./*.txt; do mv -v ”$file” ”${file%.*}.log”; done
renamed './file10.txt' -> './file10.log'
renamed './file1.txt' -> './file1.log'
renamed './file2.txt' -> './file2.log'
renamed './file3.txt' -> './file3.log'
renamed './file4.txt' -> './file4.log'
for
を使用する代わりに 上記のループでは、prename
をインストールできます 次のようにコマンドを実行して上記の目標を達成します:
$> prename -v 's/.txt/.log/' *.txt
file10.txt -> file10.log
file1.txt -> file1.log
file2.txt -> file2.log
file3.txt -> file3.log
file4.txt -> file4.log
多くの場合、構成ファイルを変更するときは、基本的なコピーコマンドを使用して元のファイルのバックアップコピーを作成します。例:
$> cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth0.back
ご覧のとおり、パス全体を繰り返してファイルに.backを追加することは、それほど効率的ではなく、おそらくエラーが発生しやすくなります。これを行うには、より短く、よりきちんとした方法があります。ここに来る:
$> cp /etc/sysconfig/network-scripts/ifcfg-eth0{,.back}
ファイルまたは変数に対してさまざまなチェックを実行できます。 help test
を実行します 詳細については。
次のコマンドを使用して、ファイルがシンボリックリンクであるかどうかを確認します。
$> [[ -L /path/to/file ]] && echo “File is a symlink”
これが私が最近遭遇した問題です。一度にたくさんのファイルをgunzip/untarしたかったのです。考えずに次のように入力しました:
$> tar zxvf *.gz
結果は次のとおりです。
tar: openvpn.tar.gz: Not found in archive
tar: Exiting with failure status due to previous errors
tarファイルは次のとおりです。
iptables.tar.gz
openvpn.tar.gz
…..
なぜそれが機能しなかったのか、そしてなぜls -l *.gz
代わりに動作しますか?内部的には、次のようになります。
$> tar zxvf *.gz
次のように変換されます:
$> tar zxvf iptables.tar.gz openvpn.tar.gz
tar: openvpn.tar.gz: Not found in archive
tar: Exiting with failure status due to previous errors
tar
コマンドはiptables.tar.gz内でopenvpn.tar.gzを見つけることが期待されています。単純なfor
でこれを解決しました ループ:
$> for f in ./*.gz; do tar zxvf "$f"; done
iptables.log
openvpn.log
Bashを使用してランダムなパスワードを生成することもできます!次に例を示します:
$> alphanum=( {a..z} {A..Z} {0..9} ); for((i=0;i<=${#alphanum[@]};i++)); do printf '%s' "${alphanum[@]:$((RANDOM%255)):1}"; done; echo
OpenSSLを使用する例を次に示します。
$> openssl rand -base64 12
JdDcLJEAkbcZfDYQ
ファイルを1行ずつ読み取る
たくさんのIPアドレスを持つファイルがあり、それらのIPアドレスを操作したいとします。たとえば、dig
を実行したい ファイルにリストされているIPアドレスの逆引きDNS情報を取得します。コメント(#またはハッシュタグ)で始まるIPアドレスもスキップしたい。
例としてfileAを使用します。その内容は次のとおりです。
10.10.12.13 some ip in dc1
10.10.12.14 another ip in dc2
#10.10.12.15 not used IP
10.10.12.16 another IP
各IPアドレスをコピーして貼り付けてから、dig
を実行できます。 手動:
$> dig +short -x 10.10.12.13
または私はこれを行うことができます:
$> while read -r ip _; do [[ $ip == \#* ]] && continue; dig +short -x "$ip"; done < ipfile
fileAの列を交換したい場合はどうなりますか?たとえば、fileAが次のようになるようにIPアドレスを右端の列に配置します。
some ip in dc1 10.10.12.13
another ip in dc2 10.10.12.14
not used IP #10.10.12.15
another IP 10.10.12.16
実行します:
$> while read -r ip rest; do printf '%s %s\n' "$rest" "$ip"; done < fileA
Bash関数を使用する
Bashの関数は、Python、C、awk、またはその他の言語で記述されたものとは異なります。 Bashでは、1つの引数を受け入れ、「Hello world」を出力する単純な関数は、次のようになります。
func() { local arg=”$1”; echo “$arg” ; }
次のような関数を呼び出すことができます:
$> func foo
関数がそれ自体を再帰的に呼び出して、特定のタスクを実行する場合があります。例:
func() { local arg="$@"; echo "$arg"; f "$arg"; }; f foo bar
この再帰は永久に実行され、多くのリソースを利用します。 Bashでは、FUNCNESTを使用して再帰を制限できます。次の例では、再帰を5つに制限するためにFUNCNEST=5を設定しました。
func() { local arg="$@"; echo "$arg"; FUNCNEST=5; f "$arg"; }; f foo bar
foo bar
foo bar
foo bar
foo bar
foo bar
bash: f: maximum function nesting level exceeded (5)
関数を使用して、最新または最も古いファイルを取得します
特定のディレクトリにある最新のファイルを表示するためのサンプル関数は次のとおりです。
latest_file()
{
local f latest
for f in "${1:-.}"/*
do
[[ $f -nt $latest ]] && latest="$f"
done
printf '%s\n' "$latest"
}
この関数は、特定のディレクトリにある最も古いファイルを表示します:
oldest_file()
{
local f oldest
for file in "${1:-.}"/*
do
[[ -z $oldest || $f -ot $oldest ]] && oldest="$f"
done
printf '%s\n' "$oldest"
}
これらは、他の外部コマンドを呼び出さずにBashで関数を使用する方法のほんの一例です。
多くのパラメータを使用してコマンドを何度も入力していることに気付くことがあります。私がよく使用するコマンドの1つは、kubectl
です。 (Kubernetes CLI)。この長いコマンドを実行するのにうんざりしています!元のコマンドは次のとおりです:
$> kubectl -n my_namespace get pods
または
$> kubectl -n my_namespace get rc,services
この構文では、-n my_namespace
を手動で含める必要があります コマンドを実行するたびに。関数を使用してこれを行う簡単な方法があります:
$> kubectl () { command kubectl -n my_namespace ”$@” ; }
これで、kubectl
を実行できます -n namespace
と入力する必要はありません 毎回:
$> kubectl get pods
同じテクニックを他のコマンドにも適用できます。
まとめ
これらは、Bashに存在するいくつかの優れたトリックです。パート2では、検索やリモート実行の使用など、さらにいくつかの例を示します。コマンドライン管理タスクをより簡単かつ正確にするために、これらのトリックを練習することをお勧めします。
[無料のオンラインコース:Red HatEnterpriseLinuxの技術概要。 ]