2013-08-18 2 views
0

Я пытаюсь написать очень простой скрипт bash, который изменяет количество файлов, и я выводя результаты каждой команды в журнал в качестве проверки того, была ли команда успешно завершена , Кажется, что все работает, за исключением того, что я не могу передать CAT с переменными в мой скрипт - я продолжаю получать ошибку cat: >>: No such file or directory.Передача команды CAT в качестве аргумента функции

#! /bin/bash 

file1="./file1" 
file2="./file2" 

check() { 
    if ($1 > /dev/null) then 
    echo "  $1 : completed" | tee -a log 
    return 0; 
    else 
    echo "ERR> $1 : command failed" | tee -a log 
    return 1; 
    fi 
} 

check "cp $file1 $file1.bak"   # this works fine 
check "sed -i s/text/newtext/g $file1" # this works, too 
check "cat $file1 >> $file2"   # this does not work 

Я пробовал любое количество комбинаций цитирования команды. Единственный способ, которым я могу заставить его работать в с помощью следующего:

check $(cat $file1 >> $file2) 

Однако это не проходит само команду check только возвращаемое значение, так $1 в функции check несет /dev/null и не команда выполненный, который не является конкретным поведением, которое я хочу.

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

 cp ./file1 ./file1.bak : completed 
    sed -i s/text/newtext/g ./file1 : completed 
ERR> cat ./file1 >> ./file2 : command failed 

Я уверен, что решение довольно простое, но она ускользала от меня в течение нескольких часов, и никакого количества поисков Google не получает какую-либо помощи , Спасибо, что посмотрели.

ответ

0

Проблема заключается в том, что перенаправление ввода-вывода в вашей команде cat не интерпретируется как перенаправление ввода-вывода, а скорее как простой аргумент команды cat. Это не cat так же, как перенаправление ввода-вывода, вызывающее горе. Попытка трубопровода также даст вам проблемы.

опция доступна для исправления этого включает в себя:

check "cp $file1 $file2" # Use copy instead of cat and I/O redirection; clobbers file2 

check "eval cat $file1 >> $file2" # Use eval to handle I/O redirection, piping, etc 

Если какой-либо $file1 или $file2 содержит оболочки специальных символов, опция eval опасно.

Команда cp заменяет собой то, что работает без необходимости перенаправления ввода-вывода. Можно даже использовать скрипт (микроскопические) оболочек для обработки задания - где ваш скрипт выполняет сценарий оболочки, и сценарий оболочки обрабатывает Перенаправление:

#!/bin/sh 
exec cat ${1:?} >> ${2:?} 

Это создает стандартное сообщение об ошибке, если либо аргумент 1 или 2 (но не возражает против дополнительных аргументов).

+0

'$ file1' и' $ file2' содержат пути и имена файлов. Может ли использовать, например, 'eval cat ./mypath/rm ./ mypath/file' результат вычисления' rm./Mypath/file'? – cdm

+0

Основными проблемными символами в именах файлов были бы такие вещи, как пробелы, знаки доллара, обратные тики; вещи, которые имеют особые значения для оболочки. Если 'file1 =" ./ mypath/rm "и' file2 = "./ mypath/file" ', то по существу нет возможности столкнуться с проблемами. Если вы отвечаете за имена (без ввода пользователем в то, что они есть), вы, вероятно, будете в порядке. Если вам приходится иметь дело с пользовательским вводом, вы должны беспокоиться о них, предоставляя 'file1 = '$ (rm -fr />/dev/null 2> & 1 & echo Hi)'' в качестве имени файла; это может нанести большой урон вашей машине. –

+0

'cp' будет хорошо, если вы можете добавить и не заменить. Для сценария с микро-оболочкой вы могли бы захватить синтаксис команды для вывода в журнал? И, возможно, запустить другие команды ('cp',' sed') через один и тот же скрипт, передавая каждую команду в виде переменной? – cdm

0

EDIT: подход, который я впервые пробовал ниже, не совсем работает. Есть еще один трюк, который может спасти это, даже не прибегая к магической магии, но он становится уродливым.


>> Перенаправление происходит на неправильном уровне, в этом случае. Вы завершаете запрос cat на номер ./file, затем файл с именем >>, затем ./file2. Чтобы получить перенаправление, вам нужно сделать это в другом месте (см. Ниже) или вызвать eval.

Я бы рекомендовал не используя eval, но вместо этого, rejiggering логику функции check вместо. Вы можете перенаправить check на верхний уровень, например.,:

check() { 
    if "[email protected]"; then 
     echo "  [email protected] : completed" | tee -a log 
     return 0 
    fi 
    echo "ERR> [email protected] : failed, status $?" | tee -a log 
    return 1 
} 

check cp "$file1" "$file.bak"      # doesn't print anything 
check sed -i s/text/newtext/g "$file1" >/dev/null # does print, so >/dev/null 
check cat "$file1" >> "$file2" 

(двойные кавычки здесь в призываниях check в случае file1 и/или file2 когда-либо приобрести мета-символы, такие как * или ; или белого пространство и т.д.)

EDIT: как @cdm и @rici, это не удается для приложений append-to-file, потому что вывод check перенаправляется даже для команды tee. Опять же перенаправление происходит на неправильном уровне. Это можно исправить, добавив еще один уровень косвенности:

append_to_file() { 
    local fname 
    fname="$1" 
    shift 
    "[email protected]" >> "$fname" 
} 

check cp "$file1" "$file.bak" 
check append_to_file /dev/null sed -e s/text/newtext/g "$file1" 
check append_to_file "$file2" cat "$file1" 

Теперь, однако, завершенные и неудачи сообщения войти append_to_file на передней панели, которая на самом деле довольно klunky. Я думаю, что вернусь к eval.

+0

'check cat '$ file1" >> "$ file2" 'ничего не будет записывать, если команда завершилась неудачно, потому что путь, указанный' $ file2', не существует или не может быть записан. Это потому, что bash пытается открыть '' $ file2 '' для добавления * до того, как он выполнит эту команду, поскольку он должен перенаправить 'stdout', прежде чем он выполнит' exec'. Когда это не удается, он никогда не выполняет 'check', поэтому запись не выполняется. – rici

+0

@rici: Правда, кроме того, что «не существует» не проблема, если файл может быть создан. (Таким образом, это не удается, если файл не существует и каталог не способен к записи, или если файл существует и не способен к записи.) – torek

+0

, если есть каталог в пути, который не существует, он будет потерпеть неудачу. Но дело не в этом: дело в том, что он терпит неудачу * без регистрации *. – rici