1

ワイルドカードパスを使用して特定のファイルを検索するbashスクリプトに取り組んでいます。そのファイル名が見つかると、ファイル内で特定の用語を検索し、それを置き換えます。

これが私がすでにまとめたものです:

#!/bin/sh

PATH=${1}
FILENAME="$2"
SEARCHFOR="$3"

/usr/bin/clear
echo "Searching $PATH"
echo "For the file $FILENAME"
echo "With the string $SEARCHFOR"
echo "=========================="
echo "       RESULTS            "
echo "=========================="
/usr/bin/find $PATH -type f -name "$FILENAME" | /usr/bin/xargs /bin/grep -l "$SEARCHFOR"

まだ置換を追加していませんが、テスト目的でgrepを使用するだけで、grepの代わりにSEDを使用することにしました。

上記のコードでは、任意のタイプのワイルドカードパスに引用符を使用する必要があります。これを回避する方法はありますか?

./script '/home/*/public_html' php.ini module.so

引数を使って考えていたのですが、別の方法が必要です。

私の最終的な目標は、ワイルドカードパスまたはファイル名を渡すことができるbashスクリプトを用意することです。ファイルが見つかると、そのファイルを検索し、特定の用語を検索し、見つかった場合はそれを置き換えます。

とてもシンプルに聞こえますが、そうあるべきですが、bashをいじってからかなり時間が経っているので、机に頭をぶつけています... aaggghh助けて!

4

5 に答える 5

2

まず第一に、変数名を大文字で宣言するのは悪い、悪い、本当に悪い考えPATHです。特に、実際に実際のPATH環境変数を再設定するためです(echo $PATHプロンプトでaを実行するだけで、私が何を意味するのか理解できます。これが、env変数が変更されるため、/usr/bin/clear代わりに使用しなければならなかった理由の1つである可能性があります)。したがって、のような小文字の変数を使用することを常にお勧めします。clearPATHpath


あなたが直面している問題は、サブシェル内のglob拡張にあります。*使用する場合

./script '/home/*/public_html' php.ini module.so

*プロンプト(親シェル)では展開されませんが、スクリプトのサブシェル内で展開されます。しかし、あなたが使用するとき

./script /home/*/public_html php.ini module.so

これ*は親シェルで展開され(シェルが指すランダムパスが1つになります)、プログラムサブシェル内で渡されます-

たとえば、ディレクトリ/homeがあります。を実行すると、アルファベット順で最初のディレクトリに移動します。したがって、親シェルに引用符がない場合は、常に、必要なものではないことを示します。/user/apps/data$ cd */apps/home/*/home/apps

これに対する即時の救済策は以下の通りです

$set -o noglob   #unset glob expansion
$./script /home/*/public_html php.ini module.so    #your command without quotes & wildcard */
$set +o noglob   #re-set glob expansion back

また

$set -o noglob;./script /home/*/public_html php.ini module.so;set +o noglob

試して$echo *から$set -o noglob;echo *;set +o noglob、簡単な例を見てください。

警告-失敗したり、元に戻すのを忘れたりした場合noglobset +o noglob)、シェルは文字を通常の文字と同じように扱い、*展開?しないため、望ましくない結果や混乱を招く可能性があります。

于 2012-09-07T05:35:46.843 に答える
2
find $path -name \*$filenamepattern\* -exec sed -i.bak 's/find/replace/g' {} ';'
  • sed -iはファイル内を検索して置換し、ファイル保存し直します
  • ファイルをバックアップしたくない場合は、.bak部分を削除してください
  • 検索の-execオプションを活用して、少し面倒なxargsを回避します
于 2012-09-07T06:27:53.660 に答える
1

引数を並べ替えて、検索するディレクトリのリストを最後に配置するだけです。それで:

#!/bin/sh

FILENAME="${1?No filename specified}"
SEARCHFOR="${2?No target string given}"
shift; shift;
SEARCHPATH="$@"

次に、残りの部分を変更せずに(PATHの名前をSEARCHPATHに変更する以外は、PATHを変更するのは非常に悪い考えなので)、次のように呼び出すことができるはずです。

$ ./script php.ini module.so /home/*/public_html
于 2012-09-06T23:03:57.563 に答える
0
find `filepath` -name `filename`|xargs sed 's/find/replace/'

私にとっては、findとsedを使用して作業を終了します。

于 2012-09-07T06:14:47.593 に答える
0

これにより、ワイルドカードをbashスクリプトに渡す問題が解決されますが、最初の箇条書きに従ってください。

#!/bin/bash -f

directory=$1
filename=$2
searchfor=$3
replacement=$4

sedpattern=s/$searchfor/$replacement/g

find $directory -name $filename -exec sed -i.bak $sedpattern {} ';'
  • コマンドラインでこのスクリプトを呼び出すときは重要です。グロブをバックスラッシュでエスケープする必要があります。
    • % ./thisscript . \*.csv oldword newword
  • bash -fオプションは、適切なタイミングでグロブをオフにします-bashサブシェルが最初に呼び出されたとき、つまりパラメーターが解析される前。
  • 一致するすべてのファイルでコマンドexecsedを検索します
  • スクリプト内に他の定義済み変数を含むsedに検索置換パターンを渡す最も簡単な方法は、パターン自体を最初に変数に配置することです。
  • -i.bakオプションは、元のファイルをバックアップするだけでなく、置換を含む新しいファイルを作成します
于 2012-09-07T19:34:23.737 に答える