web-dev-qa-db-ja.com

sedで文字列を変更しますが、どこに行きましたか?

$ cat test-paths.txt 
test/sub2/configuration.php
test/sub3/configuration.php
test/configuration.php
test/sub1/configuration.php

$ cat find-Host-test 
#!/bin/bash
for i in `cat test-paths.txt`
 do 
  echo $i
  grep "public \$Host = '127.0.0.1';" $i
  #echo $?
  if [ $? -eq 0 ]
   then
    echo "there's config file"
    sed $i 's/$Host = 127.0.0.1/$Host = localhost/' 
    echo "changed to"
    grep "public \$Host =" $i
  fi
 done

find-Host-testを実行した結果、

$ bash find-Host-test 
test/sub2/configuration.php
    public $Host = '127.0.0.1';
there's config file
sed: can't find label for jump to `est/sub2/configuration.php'
changed to
    public $Host = '127.0.0.1';
test/sub3/configuration.php
test/configuration.php
    public $Host = '127.0.0.1';
there's config file
sed: can't find label for jump to `est/configuration.php'
changed to
    public $Host = '127.0.0.1';
test/sub1/configuration.php
    public $Host = '127.0.0.1';
there's config file
sed: can't find label for jump to `est/sub1/configuration.php'
changed to
    public $Host = '127.0.0.1';

なぜテストフォルダの「t」が消えたのですか?

3
grepmaster

sed呼び出しが間違っています。

sed 's/$Host = 127.0.0.1/$Host = localhost/' "$i"

sedのマニュアルページを参照してください:

sed [OPTION]... {script-only-if-no-other-script} [input-file]

入力ファイルは、最初ではなく最後の引数です。

興味のある補足tsedはラベルと呼ばれます。 tの後に、ラベルの名前が続きます。あなたの場合、それは先頭のtのない入力ファイル名です。したがって、sedは、sedがどこにも見つからないest/sub2/configuration.phpというラベルにジャンプしようとします。 2番目の式s///gは実行されません。

4
chaos

sedが機能しない理由は、カオスの良い答えによってすでに与えられています。

あなたがいくつかの不必要なステップを使用しているので、ファイルをループする別の方法を示すためにもう少し進んでみましょう:

_while IFS= read -r file
do
    echo "$file"
    if grep -q "public \$Host = '127.0.0.1';" "$file"; then
        echo "there's config file"
        sed 's/$Host = 127.0.0.1/$Host = localhost/' "$file"
        echo "changed to"
        grep "public \$Host =" "$file"
    fi
done < "test-paths.txt"
_

違い:

  • for i in $(cat test-paths.txt)を使用しています(バッククォートを使用していますが、引用符の付け方がわかりません)。これは問題ありませんが、_while read line; do ... done < file_を実行する美しいwhileループを使用することをお勧めします。このようにして、一度に1行ずつ読み取ります。 単語ではなく行を読むには、「while read」ループにパイプ/リダイレクトします。 のトピックに関するより広範な議論を参照してください。

  • また、バックティックの使用は非推奨です。 $()を使用することをお勧めします。ネストできるためです。 (実際、ここに回答を投稿するとき、これはさらに悪いことです:))

  • _grep "something"_をしてから_$?_ステータスを確認する必要はありません。これには_grep -q_を直接使用できます。

  • これらの提案の一部は、スクリプトを http://www.shellcheck.net/ に貼り付けることでも見つけることができます。

1
fedorqui