スクリプトの 1 つを短くしたいのですが、アイデアはあるのですが、やり方がわかりません。次のようなコードがあります。
COMMAND="find /etc -type "
case $1:
"directory") $COMMAND d
;;
esac
もちろん、これは短縮版です :) そして、$COMMAND をどこにでも書かずに、これを短縮できるようにしたいので、次のようになります。
$COMMAND <the case statement return value>
しかし、ケースの結果を格納するために変数を使用したくありません。
ありがとう :) 私が何をしたいのか理解していただけたら嬉しいです :D
編集 1: Serg が指摘したように、関数を作成して find パラメータを $1 として渡すことは可能です。関数を使わずに実行したい場合は、方法があるはずです :D Serg が解決しなかったわけではありませんが、ただ興味があるだけです :D
答え1
コードを簡素化する方法はいくつかあります。以下はコード量順に並べた解決策です。
printf
およびパラメータ置換(エラーチェックなし)xargs
およびパラメータ置換(エラーチェックなし)find
パラメータ置換のみ(エラーチェックなし)- フォールスルーケース構造 (エラーチェックの問題を解決します)
- テストロジック、xargs、パラメータ置換
- Bash関数
- 配列、forループ、テスト、&&
printf
パラメータ置換ソリューションこの関数のあまり知られていない特徴
printf
は、 を呼び出すとprintf "%c" someString
、初めその文字列の文字。したがって、パラメータ展開を伴う case ステートメントの使用を避けることができ、printf
次のようになります。xieerqi:$ cat someScript.sh #!/bin/bash find /etc -type $(printf "%c" $1 )
次を実行します:
xieerqi:$ sudo ./someScript.sh directory | head [sudo] password for xieerqi: /etc /etc/logrotate.d /etc/apm /etc/apm/event.d /etc/apm/scripts.d /etc/apm/resume.d /etc/apm/suspend.d /etc/speech-dispatcher /etc/speech-dispatcher/modules /etc/speech-dispatcher/clients
ここでの制限は、 を呼び出すプロセスをフォークすることですが
printf
、これは関数ソリューションによって回避されます。関数とケース構造はすべてネイティブの bash ツールです。xargs
パラメータ置換bashのパラメータ置換を使用すると、変数から部分文字列を切り取ることができます(たとえば、
${VAR:0:3}
の最初の3文字を取得しますVAR
)。この場合、型の最初の文字directory
またはを使用します。次に、を使用してそれをパラメータとして渡すfile
ことができます。xargs
find
echo ${1:0:1} | xargs -I {} find /etc -type {}
マニュアル
find
ページには、-type
Solaris 上の flag には大文字で表される door ファイルと呼ばれるものがあると記載されていますD
が、ここでは Linux を使用しているため、これは無視しても問題ない制限であると言えます。しかし、このコードには別の危険があります。ユーザーがパラメータ
flower
として を入力した場合$1
、文字列の最初の文字を取得するため、 を検索し続けます-type f
。言い換えると、エラーチェックはありません。find
パラメータ拡張付きパラメータ拡張をさらに進めると、次のようになります。
find /etc -type ${1:0:1}
find
基本的に、コマンドと変数の部分文字列を含むワンライナーです$1
。また、エラーチェックも行われない。フォールスルーケース構造
最後の 3 つの方法の大きな問題は、エラー チェックです。これらの方法は、ユーザーがダミーではないと信頼できる場合や、自分でコードを書いているだけの場合に適しています。Java では、コマンド
switch
を省略するだけで、複数のケースで同じコマンドを実行するステートメントを記述できますbreak
。ターミネータbash
を使用しても、同じことができます;&
。man bash
;&
の代わりに を使用すると;;
、次のパターン セットに関連付けられたリストで実行が続行されます。必要なのは、「ディレクトリ」、「ファイル」、「ブロック」などの型をテストし、パラメータ置換を使用して最初の文字を切り取るだけです。
#!/bin/bash case "$1" in "directory") ;& "file");& "block") find /etc -type ${1:0:1} ;; *) exit 1 ;; esac
5.テストロジック、xargs、パラメータ置換
Basic idea here is that we're sending $1 variable through pipe to `xargs`, which in turn substitutes it into test (again square brackets). `xargs` in turn builds the actual command that runs by replacing `{}` with whatever was passed to `xargs`. As for test command, it's simple or statement, `EXPRESSION -o EXPRESSION ` , where we test if string $1 is equal to either "file" or "directory string"
echo "$1" | xargs -I {} [ "{}" = "file" -o "{}" = "directory" ] \
&& find /etc -type ${1:0:1}
`xargs` is really useful when you need to process multiple argumens with the same command. Considering that in this case we only have one argument that needs to be processed with the same command , this can be simplified to
[ "$1" = "file" -o "$1" = "directory" ] && find /etc -type ${1:0:1}
Of course the big limitation is that if you test for more than one type, you need longer `[ EXPR1 -o EXPR2 ]` structure with multiple `-o` parts.
関数ソリューション
find
コマンドを関数内に配置し、位置パラメータを使用して呼び出すことができます。例えば:
function findStuff { find /etc -type "$1" }
ここに小さなデモがあります。
sudo
多くのファイルでは/etc
一般ユーザーには読み取り権限がないため、これを使用していることに注意してください。xieerqi:$ sudo ./someScript.sh directory | head [sudo] password for xieerqi: /etc /etc/logrotate.d /etc/apm /etc/apm/event.d /etc/apm/scripts.d /etc/apm/resume.d /etc/apm/suspend.d /etc/speech-dispatcher /etc/speech-dispatcher/modules /etc/speech-dispatcher/clients xieerqi:$ sudo ./someScript.sh file | head [sudo] password for xieerqi: /etc/hosts.deny /etc/logrotate.d/speech-dispatcher /etc/logrotate.d/pm-utils /etc/logrotate.d/rsyslog /etc/logrotate.d/yate /etc/logrotate.d/apport /etc/logrotate.d/apt /etc/logrotate.d/consolekit /etc/logrotate.d/fail2ban /etc/logrotate.d/cups-daemon xieerqi:$ cat someScript.sh #!/bin/bash function findStuff { find /etc -type "$1" } case "$1" in "directory")findStuff d ;; "file") findStuff f;; esac
配列、forループ、テスト、&&
ここでの基本的な考え方は、ユーザーの入力をリストと照合し、一致した場合には何かを行うというものです。チェックする項目の配列を作成し、テスト条件を設定し (角括弧は
test
command の別名です)、ループを実行して $1 変数をテストします。&&
演算子を使用すると、左側のものが&&
成功した場合にのみ command を実行できます。したがって、配列内にある文字列が見つかった場合は、find コマンドを実行します。${1:0:1} は、前の例で説明しました。これは、一致した型から最初の文字を切り取るパラメーター展開です。したがって、このソリューションにはエラー チェックがあり、大量のコードが 3 行 (#!
行を含めると 4 行) にまとめられています。#!/bin/bash array=("file" "directory" "block"); for TYPE in "${array[@]}"; do [ "$1" = "$TYPE" ] && find /etc/ -type ${1:0:1}; done
答え2
これを関数に組み込みます:
MyFind () {
COMMAND="find /etc -type "
case $1:
"directory") $COMMAND d
;;
esac
}
いつでも使えるようになりましたMyFind $TYPE
最初のコメントに関して
関数にcase文だけを入れることもできる
FType () {
case $1 in
"directory") echo d;;
"file") echo f;;
esac
}
COMMAND="find /etc -type "
$COMMAND $(FType $TYPE)
答え3
[[ "$1" == "directory" ]] && find /etc -type d
答え4
Serg の優れた回答から得られる、すでに幅広いオプション セットに追加するもう 1 つのアイデアです。
これには を使用できる可能性がありますalias
- おそらく、現在のやり方に若干の変更を加える必要があります。
はalias
、より大きな文字列にマップするために選択した単語であり、シェルはそれを見つけるたびにそれを展開します。おそらく最も一般的な使用例は、次のように既存のコマンドに「デフォルト」を適用することです。
alias ls='ls -a --color=auto'
ただし、既存のコマンドにちなんで名前を付ける必要はなく、宛先パターンよりも短くする必要もありalias
ません。たとえば、alias tgzcreator='tar -czvf'
alias
esは、それが定義されているシェルと存続期間を共有します。 '永続的' alias
esは、 で設定できます~/.bash_aliases
。すべきよく書かれたデフォルトの.bashrc
スクリプトなどによって自動的にソース化されます。
いくつかのヒントに注意してください:
- 特定のスクリプトで、以前に定義された がコードに干渉するかどうかを心配するのではなく
alias
、 をスキップするためにバックスラッシュを前に付けることができますalias
。たとえば、通常は誤って上書きするのを避けるためにalias
cp
を使用しますcp -i
が、一部のスクリプトでは、欲しい上書きする。(既知の未編集ユーザーを設定するようなひどい回避策は使いませんalias
!)そこで、このスクリプトでは、\cp src dst
alias
シェル スクリプト内では、デフォルトでは es がソース化されない場合があります。シェル スクリプトは、独自の非対話型シェル コピーを起動します。expand_aliases
スクリプトでオプションを設定することで、es が展開されるようにすることができます。これは次の場所から取得しました:https://stackoverflow.com/questions/2197461/how-to-set-an-alias-inside-a-bash-shell-script-so-that-is-it-visible-from-the-ou
したがって、投稿で利用可能な限られたコンテキストに基づいて、何かをしたいかもしれませんちょっとこのような:
shopt -s expand_aliases
alias get_etc_dir='find /etc -type d'
alias get_etc_fil='find /etc -type f'
あなたにとって、これは微調整なしでは機能しないかもしれません。たとえば、パラメータ化された inode タイプをエイリアスごとのサフィックスに変更します。これは、ユーザーが一般的にコードの一部を短縮する方法のもう 1 つのオプションにすぎません。いずれにせよ、私は自分の知識に基づいて包括的に説明しようとしました。どこかで役立つことを願っています。
(また、Ubuntu に特化していないものについてはこれが理想的だと仮定すると、これを Unix/Linux SE に移行することをお勧めします。)