Как заменить цитату в скрипте bash?

348
Walter Schrabmair

У меня есть скрипт bash

 #!/bin/bash find . -type f > /home/wschrabi/filenames while read filename; do stripped="$(printf '%s\n' "$filename" | tr -d -C '[[:alnum:]][[:space:]][!\"\#\$\%\&\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_`{|}~]')"; ohne="$(sed -e 's/[\d126-\d255\"*:<>\?\\\|]/_/g' <<<$filename)"; test "$filename" = "$stripped" || printf "mv '%s' '%s'\n " "$" "$";  done < /home/wschrabi/filenames 

и в части $я хотел бы заменить одну кавычку в имени файла. Цель должна состоять в том, чтобы, когда я направлял вывод в сценарии bash, я хотел бы автоматически переименовывать все имена файлов. Но одиночные кавычки создают проблемы.

Большое спасибо за любые советы. Вальтер

РЕДАКТИРОВАТЬ: Вот для завершения мой Chekc NTFS для сценария имени файла.

 #!/bin/bash # # Quote a string, wrapping it in tick marks ('), and escaping any # embedded ticks. # # Inputs: # $1: The string to quote # # Returns: # (stdout) - The quoted string # quote() { if [ $(echo "$@" | tr -d "\n" | wc -c) -eq 0 ]; then echo "''" elif [ $(echo "$@" | tr -d "[a-z][A-Z][0-9]:,.=~_/\n-" | wc -c) -gt 0 ]; then echo "$@" | sed -e "s/'/\'\"\'\"\'/g" | sed -e "s/^/'/g" -e "s/$/'/g" else echo "$@" fi }  if [ $# -eq 0 ] then echo "No arguments supplied: USAGE: checkNTFS_filenames.sh <file_to_check>"  fi  if [ $# -eq 1 ] then  #find . -type f > /home/wschrabi/filenames2 while read filename; do stripped="$(printf '%s\n' "$filename" | tr -d '\"\*\:\<\>\?\\\|')"; ohne="$(sed -e 's/[\d126-\d255\"*:<>\?\\\|]/_/g' <<<$filename)"; if [ "$filename" != "$stripped" ] ; then printf "mv %s %s\n" "$(quote "$filename")" "$(quote "$stripped")"  fi done < $1 fi 
2
Я добавил еще один ответ, не для того, чтобы отвлечь внимание от virtex, и это правильно, но чтобы указать на более короткие и эффективные способы сделать это. Вот и все. MariusMatutiae 7 лет назад 0

2 ответа на вопрос

0
virtex

Если вы поместите имена файлов между отметками, экранирование символов с обратной косой чертой не будет работать. Хотя есть и другой способ сделать это. Вот функция цитаты, которую я использовал в прошлом, которая может быть полезна для вас.

# # Quote a string, wrapping it in tick marks ('), and escaping any # embedded ticks. # # Inputs: # $1: The string to quote # # Returns: # (stdout) - The quoted string # quote() { if [ $(echo "$@" | tr -d "\n" | wc -c) -eq 0 ]; then echo "''" elif [ $(echo "$@" | tr -d "[a-z][A-Z][0-9]:,.=~_/\n-" | wc -c) -gt 0 ]; then echo "$@" | sed -e "s/'/\'\"\'\"\'/g" | sed -e "s/^/'/g" -e "s/$/'/g" else echo "$@" fi } 

Когда вы запускаете его, вы получаете такие результаты.

$ quote abc abc $ quote "abc'def" 'abc'"'"'def' $ quote \"abc\" '"abc"' $ quote "abc def" 'abc def' 

Идея в том, что вы можете заменить последний printf в вашем скрипте следующим образом:

printf "mv %s %s\n" "$(quote "$filename")" "$(quote "$ohne")" 

Используя имя файла abc'def с вашим скриптом с указанным выше изменением, я получил это в качестве вывода.

mv 'abc'"'"'def' abcdef 

и успешно переименовал файл при выполнении.

Большое спасибо логи Walter Schrabmair 7 лет назад 0
0
MariusMatutiae

Ответ Virtex, конечно, совершенно правильно. Я просто хотел бы отметить, что такого рода операции проще выполнять с массивами Bash : просто чтобы прояснить ситуацию, давайте предположим, что мы хотим удалить начальные символы ./, которые находят листья в именах файлов в этой простой команде :

find -maxdepth 1 -type f 

Это можно сделать следующим образом:

#!/bin/bash  declare -a mylist mylist=(`find -maxdepth 1 -type f `) mylist=($) echo "$" 

Поиск и замена Bash работает с массивами, как можно было бы надеяться: изменяя элементы массива один за другим. Это может быть изменено, чтобы включить ваш пример.

РЕДАКТИРОВАТЬ :

Что делать, если у меня есть миллионы файлов?

Как насчет 10 миллионов?

$ time /bin/bash -c 'unset array && declare -a array && array=($(seq 1 10000000)) && echo "$"; unset array' 7  real 0m11.110s user 0m10.412s sys 0m0.724s  $ inxi -C CPU: Dual core Intel Core i7-5500U (-HT-MCP-) cache: 4096 KB  clock speeds: max: 3000 MHz 1: 2509 MHz 2: 2471 MHz 3: 2631 MHz 4: 2471 MHz 
Спасибо Мариус, но что, если у меня есть миллионы файлов? Будет ли предел оперативной памяти для массивов bash? Walter Schrabmair 7 лет назад 0
@WalterSchrabmair Пожалуйста, смотрите мой Edit. MariusMatutiae 7 лет назад 0

Похожие вопросы