循环遍历名称中带有空格的文件,从每个文件中的第一个字符创建新文件夹并将文件移动到文件夹

循环遍历名称中带有空格的文件,从每个文件中的第一个字符创建新文件夹并将文件移动到文件夹

我正在尝试执行这个 bash 脚本,该脚本循环当前目录中的文件(名称中包含空格),并使用该文件的第一个字符创建一个新文件夹(如果尚未创建),然后将该文件移动到该文件夹。这是我的代码:

for i in `/bin/ls | xargs`
do
    dir=`echo "$i" | cut -c 1 -`
    mkdir -m777 -p "$dir"
mv "$i" "$dir"
done

这样做的问题似乎是它将文件中的每个单词视为一个单独的文件,因此尽管它正确创建了文件夹,但它无法将文件移动到该文件夹​​,因为它查找的文件的名称是仅实际文件的第一个单词。我查看了类似问题的其他答案,但这是我能得到的最接近的答案。

编辑:我/bin/ls | xargs 按照@steeldriver的建议将“ for i in ”替换为“ for i in * ”,尽管它解决了我原来的问题,但我收到了如下错误:

mv: cannot move '`' to a subdirectory of itself, '`/`'
mv: invalid option -- ' '
mv: missing destination file operand after '-'
mv: invalid option -- '.'
mv: invalid option -- ')'
mv: invalid option -- '+'
mv: cannot move ''$'\340' to a subdirectory of itself, ''$'\340''/'$'\340'
mv: cannot move ''$'\303' to a subdirectory of itself, ''$'\303''/'$'\303'
mv: cannot move ''$'\305' to a subdirectory of itself, ''$'\305''/'$'\305'
mv: invalid option -- '1'

我认为其中一些文件可能以非ascii字符开头(我无法查看内容,因为文件太多)。有解决办法来处理这些情况吗?

答案1

要循环名称中包含空格的文件,shell 足够了,无需调用ls

for    i in *                   # * replaces the complex (and unquoted) `/bin/ls | xargs`
do
       dir=${i%"${i#?}"}        # replaces the slow subshell `echo "$i" | cut -c 1 -`

       echo "$i"                # just to show that an * is enough (and accepts spaces).
done

要处理列出的每个文件(其中包括目录),您应该检查文件名是否是文件(而不是目录),并在创建目录之前检查该目录是否不存在。

for i in *
do
    if [ -f "$i" ]; then
        dir=${i%"${i#?}"}
        if [ ! -d "$dir" ]; then
            mkdir -m777 -p "$dir"
        fi
        mv "$i" "$dir"
        if [ "$?" -ne 0 ]; then
            echo "An error occurred moving file \"$i\" to dir \"$dir\""
        fi
    fi
done

答案2

使用 GNU Parallel 时,它看起来像这样:

parallel 'mkdir -p {=s/(.).*/$1/=}; mv {} {=s/(.).*/$1/=}' ::: *

(编辑:刚刚注意到您正在要求文件 - 不是目录。/已删除)。

相关内容