Проблема с обработкой нескольких файлов, подсчетом строк

Поскольку строки в кавычках заключены в двойные... двойные кавычки, они вообще не заключаются в кавычки.

У вас есть:

find /log/ -mtime -31 -type f -name ""*data.txt"" -printf ""cp -p %p /Backup/%Td/\n"" | sh

Это должно быть:

find /log/ -mtime -31 -type f -name "*data.txt" -printf "cp -p %p /Backup/%Td/\n" | sh

Возможно, вам не следует этого делать. Вы должны использовать find -execдля копирования этих файлов.

-3
20.05.2021, 17:05
1 ответ

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

Вместо того, чтобы исправлять этот аспект сценария, давайте переосмыслим то, что вы хотите сделать.

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

Скрипт мог бы выглядеть так:

#!/bin/sh -

wc -l -- "$@"

Тестирование без сохранения вывода:

$./script.sh cat dog cow
       5 cat
       2 dog
      14 cow
      21 total

Вызов скрипта с несуществующим именем файла:

$./script.sh cat dog cow hamster
       5 cat
       2 dog
      14 cow
wc: hamster: No such file or directory
      21 total

Сохранение вывода в файле:

$./script.sh cat dog cow hamster >output
wc: hamster: No such file or directory
$ cat output
       5 cat
       2 dog
      14 cow
      21 total

"$@"в сценарии будет заменен списком аргументов командной строки, каждый из которых заключен в кавычки. Это означает, что если вы вызовете свой сценарий с cat, dogи cowв командной строке, "$@"в сценарии расширится до этого списка.

Утилита wcуже выполняет все необходимые действия, включая предоставление общего итога по всем данным файлам, поэтому все, что нам нужно сделать, это вызвать ее с опцией -lдля имен файлов, перечисленных в командную строку скрипта, чтобы заставить его считать строки.

По умолчанию вывод записывается в стандартный вывод.Это дает пользователю сценария свободу легко перенаправлять вывод туда, куда он хочет.

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

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

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

#!/bin/sh -

if [ "$#" -eq 0 ]; then
    echo 'expected to get filename argument(s)' >&2
    exit 1
fi

wc -l -- "$@"

Здесь рассматривается значение $#, которое представляет собой количество аргументов командной строки, полученных сценарием. Если это ноль, оператор ifперейдет к оператору echo, который выведет диагностическое сообщение, а затем завершит сценарий.

#!/bin/sh -

wc -l -- "${@?expected to get filename argument(s)}"

Это делает то же самое, но использует совсем другую механику. Расширение ${variable?word}приведет к тому, что диагностическое сообщение в wordбудет записано на выход, если "$@"пусто или не установлено, а также завершит выполнение скрипта.

Это может выглядеть так:

$./script.sh
./script.sh[3]: @: expected to get filename argument(s)
1
28.07.2021, 11:31

Теги

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