сценарий оболочки для пакетной замены определенной строки в CSV-файле - PullRequest
1 голос
/ 16 июня 2019

Я хочу заменить некоторые строки в моем сыром csv-файле для дальнейшего использования, и я до сих пор ищу Интернет и создаю сценарий.Но, похоже, они не работают.Надеюсь, что кто-нибудь может мне помочь

Файл CSV выглядит следующим образом, и я хочу удалить «^ M» и «# Columns:», чтобы я мог прочитать свой файл.

# Task: bending1^M
# Frequency (Hz): 20^M
# Clock (millisecond): 250^M
# Duration (seconds): 120^M
# Columns: time,avg_rss12,var_rss12,avg_rss13,var_rss13,avg_rss23,var_rss23^M
#!/usr/bin/env bash
function scandir(){
cd `dirname $0`
echo `pwd`
local cur_dir parent_dir workir
workdir=$1
cd ${workdir}

if [ ${workdir}="/" ]
then 
    cur_dir=""
else
    cur_dir=$(pwd)
fi

for dirlist in $(ls ${cur_dir})
do
    if test -d ${dirlist}
    then
        cd ${dirlist}
        scandir ${cur_dir}/${dirlist}
        cd ..
    else
        vi ${cur_dir}/${dirlist} << EOF
        :%s/\r//g
        :%s/\#\ Columns:\ //g
        :wq
        EOF
    fi
done
}

Ответы [ 3 ]

1 голос
/ 16 июня 2019

Хорошо опубликованный ответ является исправлением, но я бы рекомендовал следующий синтаксис:

find "$1" -type f -name '*.csv' -exec sed -e 's/\r$//;s/^# Columns: //' -i~ {} +
  • Использование + вместо \; в конце команды поиска позволит sedработать со многими файлами одновременно, сокращая количество разветвлений и ускоряя всю работу.

  • Опция ~ после -i позволяет переименовывать существующие файлы, добавляя тильду в конце имен вместоудаляя их.

  • Использование -type f обеспечит работу только с файлами (без символических ссылок, каталогов, сокетов, fifos, устройств ...)

1 голос
/ 16 июня 2019

Весь ваш скрипт выглядит так:

find "$workdir" -type f | xargs -n1 sed -i -e 's/\r//g; s/^# Columns://'

Примечания к вашему скрипту:

  • Проверьте ваши скрипты на действительность https://www.shellcheck.net/
  • Из<< EOF здесь документ недействителен.Закрывающее слово EOF должно начинаться с начала строки внутри скрипта:

    vi ${cur_dir}/${dirlist} << EOF
    :%s/\r//g
    :%s/\#\ Columns:\ //g
    :wq
EOF
#^^ no spaces in front of EOF, also no spaces/tabs after EOF
# the whole line needs to be exactly 'EOF'

Не может быть пробелов, табуляцииперед ней.Кроме того, я не думаю, что vi - не лучший инструмент для выполнения подстановок в файле, также я не знаю, как он работает с вкладками или пробелами перед :.Возможно, вы захотите запустить его без пробельных символов перед ::

    vi ${cur_dir}/${dirlist} << EOF
:%s/\r//g
:%s/\#\ Columns:\ //g
:wq
EOF
  • Обратные метки ` устарели , менее читабельны и не позволяют легковложенности.Вместо этого используйте $( ... ) подстановку команд.
  • echo `pwd` - просто недопустимое использование echo, просто используйте pwd.
  • for dirlist in $(ls парсинг вывода ls плохой .Вместо этого используйте команду find или, если необходимо, глобуляцию оболочки, т.е.for dirlist in *.
  • if [ ${workdir}="/" ] недействительно.Это проверяет, является ли строка "${workdir}=/ не нулевой.Bash учитывает пробел, ему нужно пространство между = и операндами.Это должно быть if [ "${workdir}" = "/" ].
  • Всегда указывайте ваши переменные .Не cd ${dirlist} делать cd "${dirlist}" и т. Д.
0 голосов
/ 16 июня 2019

Вы можете сократить весь сценарий до одной команды, и вам не нужно использовать Vim для обработки файлов:

find ${workdir} -name '*.csv' -exec sed -i -e 's/\r$//; /^#/d' '{}' \;

Пояснение:

  • find <dir> -name <pattern> -exec <command> \; будет искать <dir> for files matchingand execute `в каждом файле. Вы хотите найти CSV-файлы и что-то с ними сделать (выполнить для них команду).

  • Команда для каждого найденного файла (CSV) будет sed -i -e 's/\r$//; /^#/d'. Это означает редактировать файлы на месте (-i) и выполнить для них два преобразования. s/\r$// удалит ^M из каждой строки, а /^#/d удалит все строки, начинающиеся с #.

  • '{}' заменяется файлами, найденными с помощью find, а \; отмечает конец выполнения команды с помощью find (см. Страницу руководства find для этого).

Большая часть вашего скрипта эмулирует часть команды find. Это не очень хорошая идея.

Кроме того, для простой обработки текста проще и быстрее использовать sed вместо вызова редактора, такого как Vim.

...