удалять конечные пробелы из текстовых файлов ТОЛЬКО при необходимости

Может быть скрипт типа:

#! /bin/sh -
dir=${1?Please specify the directory to sort}
cutoff=${2:-1048576} # bytes

cd -P -- "$dir" || exit
mkdir -p -- small_files large_files || exit

find. ! -name. -prune -type f '(' \
  -size "+${cutoff}c" -exec sh -c 'exec mv -- "$@" large_files' sh {} + -o \
                      -exec sh -c 'exec mv -- "$@" small_files' sh {} + ')'

В системе GNU вы можете передать параметр -vв mvи mkdir, чтобы сделать его более подробным. С помощью инструментов GNU это можно упростить до:

#! /bin/sh -
dir=${1?Please specify the directory to sort}
cutoff=${2:-1M}

cd -P -- "$dir" || exit
mkdir -p -- small_files large_files || exit

find. -maxdepth 1 -type f '(' \
  -size "+$cutoff" -exec mv -t large_files {} + -o \
                   -exec mv -t small_files {} + ')'

С этой опцией -tдля указания целевого каталога нам больше не нужно вызывать shдля вставки списка имен файлов в середину аргументов mv.

Вы можете добавить дополнительные категории, например:

find. -maxdepth 1 -type f '(' \
  -size +1M   -exec mv -t large_files  {} + -o \
  -size +100k -exec mv -t medium_files {} + -o \
              -exec mv -t small_files  {} + ')'

С помощью zshвы также можете сделать это как:

#! /bin/zsh -
dir=${1?Please specify the directory to sort}


cd -P -- "$dir" || exit

for size target (
  LG+1   huge_files
  LM+100 very_large_files
  LM+1   large_files
  LK+100 medium_sized_files
  L+100  small_files
  ''     tiny_files
) {
  mkdir -p $target || exit
  files=(*(NDoN.$size))
  (($#files == 0)) || mv -- $files $target || exit
}
3
02.11.2021, 16:52
2 ответа

Один из способов может быть с find/grep/sed, как показано:

find. -maxdepth 1 -type f -name '*.txt' \
  -exec grep -q '[[:blank:]]$' {} \; \
  -exec sed -Ei -e 's/[[:blank:]]+$//' {} +
  • поиск с -maxdepth, если 1 работает в текущем каталоге.
  • {} \;относится к имени файла, передаваемого в grep, а \;экранирует точку с запятой метасимвола оболочки, которая является индикатором конца команды. Мы выходим из него так, чтобы он достиг -exec. В качестве альтернативы вы могли бы написать это как';'
  • {} +вы уже знаете {}сейчас, и что +означает, что вы передаете как можно больше имен файлов вsed(в основном,вместо передачи единственного {}текущего результата find, накопите список {}для использования в качестве аргумента перед вызовомsed). Это позволяет минимизировать количество sedвызовов.
7
03.11.2021, 03:56

Следующее строится на идее roaima запускать выражение sedво всех файлах, но затем сохранять только те файлы, которые были фактически изменены.

Он изменяет это, делая меньше sedвызовов:

printf '%s\0'./*.txt |
xargs -0 sed -i.bak 's/[[:blank:]]$//

Затем вы можете просмотреть файлы *.txt, сравнив их с оригиналами и выбрав тот, который хотите сохранить.:

for name in./*.txt; do
    if cmp -s "$name" "$name.bak"; then
        # keep original
        mv "$name.bak" "$name"
    else
        # keep modified
        rm "$name.bak"
    fi
done

Или сделать и то, и другое за один раз:

printf '%s\0'./*.txt |
xargs -0 sh -c '
    sed -i.bak "s/[[:blank:]]$//" "$@"
    for name do
        if cmp -s "$name" "$name.bak"; then
            mv "$name.bak" "$name"
        else
            rm "$name.bak"
        fi
    done' sh
2
05.11.2021, 09:01

Теги

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