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

Вы подошли близко.

  1. Перед выборочной печатью строк необходимо подавить вывод sed :

     $ cal 12 2015 | sed -n '3,7p' 
    1 2 3 4 5 
    6 7 8 9 10 11 12 
    13 14 15 16 17 18 19 
    20 21 22 23 24 25 26 
    27 28 29 30 31 
     

    Ваш sed может не иметь -n . В этом случае используйте d , чтобы удалить все строки, кроме тех, которые вам нужны.

  2. Ваша команда tr заменяет все, кроме букв, включая цифры. Просто замените пробелы:

     $ cal 12 2015 | sed -n '3,7p' | tr -s '' '\ n' 
     
    1 
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
    10 
    11 
    12 
     
0
13.09.2018, 18:09
2 ответа

Ваш сценарий должен принимать более двух аргументов.

Прежде чем оболочка выполнит grepв команде

grep -l "my text" file*.ext

шаблон подстановки имен файлов file*.extрасширяется до всех совпадающих имен файлов. Таким образом, командная строка, которая будет запущена в конце, будет

grep -l "my text" file1.ext file2.ext file3.ext

(если это файлы, соответствующие шаблону)

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

#!/bin/sh

pattern=$1
shift

grep -l -e "$pattern" "$@" | xargs ls -lrt

Здесь шаблон сохраняется в переменной, а затем удаляется из списка аргументов командной строки. Остальные аргументы представляют собой список имен файлов (, если шаблон подстановки имен файлов в командной строке соответствует )и доступен в "$@".

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

Я удалил параметр -aиз ls, так как он не нужен при указании явных имен файлов в список. Я также использую grepс -eдля указания шаблона, так как шаблон с начальным дефисом(-)в противном случае может сбить с толку grep.


Если бы не сортировка, я бы предложил следующую findкоманду вместо вашего пайплайна (правильно обрабатывает имена файлов с пробелами и символами новой строки):

find. -type f -name "$filepattern" -exec grep -q -e "$pattern" {} ';' -ls

Это ищет файлы с именами, соответствующими тому, что находится в $filepattern, и с содержимым, соответствующим тому, что находится в $pattern, а затем производит ls -l-, как вывод. Поиск выполняется рекурсивно в текущем каталоге.

Как часть скрипта:

#!/bin/sh

pattern=$1
filepattern=$2

find. -type f -name "$filepattern" -exec grep -q -e "$pattern" {} ';' -ls

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

$./script.sh 'my text' 'file*.ext'
1
28.01.2020, 02:31

Чтобы сделать его немного безопаснее, но полагаясь на расширения GNU:

#! /bin/sh -
pattern=${1?pattern required}; shift
: "${1?no filename specified}"
grep -l --null -e "$pattern" -- "$@" |
  xargs -r0 ls -lrtd --

С помощью --null/ -0мы избегаем проблем с именами файлов, которые содержат пробелы, кавычки или обратную косую черту.

Используя -e "$pattern", мы избегаем проблем с шаблонами, начинающимися с -.

Используя --, мы избегаем проблем с именами файлов, начинающимися с -.

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

С помощью -rмы избегаем перечисления текущего каталога, если нет соответствующего файла.

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

Также обратите внимание, что -будет означать stdin для grep, но файл с именем -в текущем каталоге для ls. GNU grep -lвыведет(standard input)(или его перевод на ваш язык ). Если вы хотите указать файл с именем -в текущем каталоге, используйте ./-вместо -.

1
28.01.2020, 02:31

Теги

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