如何让'for in'不分割字符串

时间:2015-10-20 02:52:46

标签: string bash shell split find

我正在尝试重命名几个文件。所以我首先需要这些文件名。 我正在使用:

for FILE in $(find . -type f -name "*.flv" -exec basename {} \; ); do
    echo "$FILE"
done

当我尝试使用find命令时,它会正确返回文件数,但是当我使用for时,我希望ARQ包含单个文件的整个名称,而是返回分割后的单词文件名。 那么如何获得整个名称,而不仅仅是它的单词呢?

4 个答案:

答案 0 :(得分:3)

有几种方法可以让它发挥作用。最简单的是完全使用find exec

find . -type f -name "*.flv" -exec bash -c 'f=$(basename "$1"); printf "%s\n" "$f"' _ {} \;

换句话说,如果您愿意,可以在-exec子句中放置复杂的脚本。

作为第二选择,请考虑这个循环:

find . -name '*.flv' -print0 | while IFS= read -d '' -r file
do 
   f=$(basename "$file")
   printf "%s\n" "$f"
done

答案 1 :(得分:2)

for循环与Command Substitution的结果一起使用,不带双引号,默认情况下会导致结果为break on space, tab and newline(默认值为IFS)。

POSIXly,除了find和内联脚本之外,您不需要任何其他内容:

$ find . -type f -name "*.flv" -exec sh -c '
  for f do
    printf "%s\n" "${f##*/}"
  done
' sh {} +

使用GNU查找,您不需要内联脚本:

$ find . -type f -name "*.flv" -printf '%f\n'

答案 2 :(得分:1)

查看问题的标题:避免使用in in分割字符串:

不要在循环中使用IFS字段分隔符:

:~> a="sdad asd asda  ad
> fdvbdsvf
> dfvsdfv
> 4"

:~> for s in $a; do
       echo "== $s =="; 
    done
== sdad ==
== asd ==
== asda ==
== ad ==
== fdvbdsvf ==
== dfvsdfv ==
== 4 ==

:~> (IFS=; for s in $a; do
       echo "== $s =="; 
     done)
== sdad asd asda  ad
fdvbdsvf
dfvsdfv
4 ==

我在最后一个命令中使用了圆括号,因此IFS的更改值仅限于该子进程。

答案 3 :(得分:0)

而不是使用find,使用rename命令来重命名多个文件。

例如:

rename 's/foo/bar/' **/*.flv

将文件名中的foo递归地替换为所有bar文件中的*.flv。如果您的shell支持a new globbing option(例如Bash 4.x或zsh),请确保该选项已由shopt -s globstar启用。

或者,如果您在循环中使用find,则可以使用:

    管道到-print0xargs)等外部程序
  • -0
  • 使用-exec cmd直接在文件({}
  • 上运行命令
  • 使用-execdir cmd在文件所在的目录中执行命令