2

特定のディレクトリからすべてのファイル名を読み取り、別のディレクトリに文字列を追加して、それらの名前で新しいファイルを作成したいと考えています。

例 > 'A'、'B'、'C' が 'logs' ディレクトリにある場合、スクリプトは 'A_tmp'、'B_tmp'、'C_tmp' を 'tmp' ディレクトリに作成する必要があります

私が使っているのは -

tempDir=./tmp/
logDir=./logs/

for file in $( find `echo $logDir` -type f )
 do
      name=eval basename $file
      echo $name
      name=$(echo $name | sed 's/.$//')
      echo $tempDir
      opFile=$tempDir$name
      echo $opFile
 done

しかし、私が理解したのは、 $file には最後の文字として '\n' が含まれており、文字列を連結できないということです。

現在、私はファイルを作成しておらず、すべての名前を出力しているだけです。

では、ファイル名から「\ n」を削除するにはどうすればよいですか?私の理解は正しいですか?

4

4 に答える 4

6

分析

スクリプトには対処すべき問題が複数あります。それを一歩一歩見てみましょう:

tempDir=./tmp/
logDir=./logs/

for file in $( find `echo $logDir` -type f )

このスキームは、ファイル名にスペースが含まれていないことを前提としています (これは珍しい制限ではありません。名前にスペースが含まれる問題を回避するのは比較的難しいことです)。また、echo;は必要ありません。書くだけ:

for file in $(find "$logDir" -type f)

続き:

do
    name=eval basename $file

これbasenameにより、環境変数nameが値evalと引数に設定された状態でコマンドが実行されます$file。ここで必要なものは次のとおりです。

    name=$(basename "$file")

名前にスペースを含めることはできないため、二重引用符は厳密には必要ありません (ただし、名前にスペースが含まれることがあるため、すべてのファイル名を引用するのは悪い習慣ではありません)。

    echo $name

name が設定されていないため、空白行がエコーされます。

    name=$(echo $name | sed 's/.$//')

name が設定されている場合、最後の文字が切り落とされますが、 name が の場合、A何も残りません。

    echo $tempDir
    opFile=$tempDir$name
    echo $opFile
done

二重引用符を付けるか取るか、_tmp接尾辞をopFileに追加していないという事実は、残りに問題はありません。

合成

変更をまとめると、次のようになります。

tempDir=./tmp/
logDir=./logs/

for file in $(find "$logDir" -type f)
do
    name=$(basename "$file")
    echo "$name"                    # Debug only
    echo "$tempDir"                 # Debug only
    opFile="$tempDir${name}_tmp"
    echo "$opFile"
done

これは、すべての中間結果を示しています。それを次のように完全に圧縮できます。

tempDir=./tmp/
logDir=./logs/

for file in $(find "$logDir" -type f)
do
    opFile="$tempDir"$(basename "$file")"_tmp"
    echo "$opFile"
done

または、名前にスペースが含まれていないため、二重引用符のより単純な組み合わせを使用します。

tempDir=./tmp/
logDir=./logs/

for file in $(find "$logDir" -type f)
do
    opFile="$tempDir$(basename $file)_tmp"
    echo "$opFile"
done

もちろん、エコーは、実行する予定のコピーまたは移動操作の代理として存在します。

編集: ...そして、スペースとグロビング文字を含むファイル名の制限を削除するには、次のようにします。

tempDir=./tmp/
logDir=./logs/

find "$logDir" -type f |
while IFS= read -r file
do
    opFile="${tempDir}${file##*/}_tmp"
    echo "$opFile"
done

改行を含むファイル名では失敗します。それを処理したい場合は、find ... -print0 | xargs -0またはを使用して解決策を調査してくださいfind ... -exec

于 2012-12-06T05:19:44.563 に答える
2

以下を試してください。

#!/bin/sh

tmpDir=./tmp/
logDir=./logs/

# list all files in log directory, pipe into a loop that reads each path line
# by line..
# Also note that there is no newline in this case since it is swallowed by 'read'.
find $logDir -type f | while read path; do
    # get the basename of the path
    name=`basename $path`
    # copy the found file to the temporary directory.
    dest="$tmpDir/${name}_tmp"
    echo $dest
done

シェル スクリプトには、 $tmpDir/${name}_tmpで示されているように、ステートメント内で文字列を簡単に連結する機能があります。 read は改行を飲み込むため、出力を置き換える必要はありません。

find ... readは、何かの複数行を読み取りたい場合に非常に便利な構造ですが、ファイルに対しても機能します。

while read line; do
    echo $line
done < filename.txt

編集:明確化

于 2012-12-06T04:53:00.973 に答える
1

次のようなことを試してください:

tempDir=./tmp/
logDir=./logs/

for file in $( find `echo $logDir` -type f )
  do
    name=`eval basename $file|tr -d "\n"`_tmp
    echo $name
  done
于 2012-12-06T04:45:51.287 に答える
0

変えたら

name=eval basename $file

name=`eval basename $file`

afterwads の名前には、必要なものが含まれています。

于 2012-12-06T04:46:22.537 に答える