2

我想从特定目录中读取所有文件名,然后通过在另一个目录中附加一些字符串来创建具有这些名称的新文件。

例如 > 'A', 'B', 'C' 在 'logs' 目录中然后脚本应该在 'tmp' 目录中创建 'A_tmp', 'B_tmp', 'C_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设置为 valueeval和 argument的情况下运行命令$file。你需要的是:

    name=$(basename "$file")

双引号不是绝对必要的,因为名称不能包含空格(但是引用所有文件名并不是一个坏习惯,因为有时名称确实包含空格)。

    echo $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 -0or调查解决方案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

Shell 脚本能够在语句中轻松连接字符串,如$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`

然后之后的名称包含您想要的内容。

于 2012-12-06T04:46:22.537 回答