重命名名称由多个单词组成的文件夹

时间:2014-12-16 10:03:38

标签: bash

开始我有这样一个剧本:

#!/bin/bash

for i in *; do
if [ -d "$i" ]; then
    if [ "$i" == $(grep $i names.txt | cut -d ' ' -f 1) ]; then
        mv $i $(grep $i names.txt | cut -d ' ' -f 2)
    else
        echo "The word $i wasn't found in the dictionary"
    fi
fi
done

使用字典(names.txt)重命名文件,哪一行是模式" english_word german_one"。

one eins
two zwei
my mein
your dein

问题是:它仅适用于名称单字的文件。 "一个"成为" eins", " 2"变成" zwei",但是"一个两个"不会成为" eins zwei"。 如何重命名名称包含多个单词的文件,例如"我的文档","第一个文件夹"等? 我知道我必须以某种方式标记文件夹名称,但不知道如何。 bash的新手。 提前谢谢。

4 个答案:

答案 0 :(得分:2)

这是一个相当普遍的纯Bash解决方案:我们将文件夹名称标记化,然后对名称中的每个单词执行翻译。在此之前,我们将字典加载到哈希数组中:

#!/bin/bash

# load dictionary
declare -A dictionary=()
while read -r eng ger; do
    [[ $eng ]] && [[ $ger ]] || continue
    dictionary[$eng]=$ger
done < dictionary_file

tokenize() {
    # Split $1 into two arrays:
    # tokenize_sep consists of all the non-alpha strings
    # tokenize_alpha consists of all the alpha strings
    # We have: $1=${tokenize_sep[0]}${tokenize_alpha[0]}${tokenize_sep[1]}${tokenize_alpha[1]} ...
    local var=$1
    tokenize_sep=() tokenize_alpha=()
    while [[ $var ]]; do
        [[ $var =~ ([^[:alpha:]]*)(.*) ]]
        tokenize_sep+=( "${BASH_REMATCH[1]}" )
        var=${BASH_REMATCH[2]}
        [[ $var =~ ([[:alpha:]]*)(.*) ]]
        tokenize_alpha+=( "${BASH_REMATCH[1]}" )
        var=${BASH_REMATCH[2]}
    done
}

translate_ary() {
    # Translates each word given as arguments according to hash array dictionary
    # Returned array is translate_ary_ret
    local w t
    translate_ary_ret=()
    for w; do
        if [[ $w ]]; then
            t=${dictionary[$w]}
            [[ $t ]] || t=$w
        else
            t=
        fi
        translate_ary_ret+=( $t )
    done
}

intertwine() {
    # $1 and $2 are two array names
    # returns a string intertwine_ret that consists of all fields of $1 and $2 intertwined (shuffled)
    local ary1=$1[@] ary2=$2[@] i
    ary1=( "${!ary1}" ) ary2=( "${!ary2}" )
    intertwine_ret=
    for((i=0;i<${#ary1[@]};++i)); do
        intertwine_ret+=${ary1[i]}${ary2[i]}
    done
}

translate() {
    # Translates string given in $1, preserving separators
    # Return string in translate_ret
    tokenize "$1"
    translate_ary "${tokenize_alpha[@]}"
    intertwine tokenize_sep translate_ary_ret
    translate_ret=$intertwine_ret
}

# Do the renaming:

for i in *; do
    translate "$i"
    [[ $i = "$translate_ret" ]] && continue
    echo mv -nv -- "$i" "$translate_ret"
done

它不是真正的单行,但应该完成这项工作。

我将此脚本称为bananachmod +x并且:

$ ls -1
banana
banana_is_my_favorite_fruit
dictionary_file
--one..my^ your-banana.one
one_two_bananas
your_two...pdf
$ ./banana
mv -nv -- banana_is_my_favorite_fruit banana_is_mein_favorite_fruit
mv -nv -- --one..my^ your-banana.one --eins..mein^ dein-banana.eins
mv -nv -- one_two_bananas eins_zwei_bananas
mv -nv -- your_two...pdf dein_zwei...pdf

没有移动任何内容:为此,请删除脚本底部echo命令前面的mv

答案 1 :(得分:1)

如果你有perl rename/prename命令&amp; awk随你而来,试试这个单行:

$ touch one; mkdir -p "one two" two # "one two" & two are directories, one is file.

$ ls -F # verify. This would probably how your structure look like.
names.txt  one  "one two/"  two/  #<~~~~"one two" quoted only for the explanation. ls does not quote it.

$ prename "$(awk '{printf "s/"$1"/"$2"/g;"}' names.txt )" */ # This will rename as per your requirement.

$ ls -F # verify
"eins zwei/"  names.txt  one  zwei/ #<~~~~ same quoting here too...

说明:

$ awk '{printf "s/"$1"/"$2"/g;"}' names.txt # generates the find/replace perl regex.
s/one/eins/g;s/two/zwei/g;s/my/mein/g;s/your/dein/g;

prename然后重命名使用perl-regex提供的文件。

*/ glob仅指定目录,即&#34;一个两个&#34; &安培; &#34;两个&#34;,忽略文件&#34;一个&#34;。

答案 2 :(得分:0)

使用正确的引语

 mv "$i" "$(grep $i names.txt | cut -d ' ' -f 2)"

双引号将处理文件名中的空格

答案 3 :(得分:0)

在谷歌踢了一段时间之后,我找到了这样的解决方案:

#!/bin/bash
for i in *; do
if [ -d "$i" ]; then
    newname=""
    del=""
    for word in $i; do
        if [ "$word" == "$(grep $word names.txt | cut -d ' ' -f 1)" ]; then
            newname="$newname""$del""$(grep $word names.txt | cut -d ' ' -f 2)"
        else
            newname="$newname""$del""$word"
        fi
        del=" "
    done
    if [ "$i" != "$newname" ]; then 
        mv "$i" "$newname"
    fi
fi
done