socat выдает ошибку (read(6, 0xf97acc0, 8192): Отказано в доступе)

Утилита cpперезапишет целевой файл, если этот файл уже существует, без запроса пользователя.

Функция, которая реализует базовую возможность cp,без использования cpбыло бы

cp () {
    cat "$1" >"$2"
}

Если вы хотите запросить пользователя перед перезаписью цели (, обратите внимание, что это может быть нежелательно, если функция вызывается не -интерактивной оболочкой):

cp () {
    if [ -e "$2" ]; then
        printf '"%s" exists, overwrite (y/n): ' "$2" >&2
        read
        case "$REPLY" in
            n*|N*) return ;;
        esac
    fi

    cat "$1" >"$2"
}

Диагностические сообщения должны направляться в стандартный поток ошибок. Это то, что я делаю с printf... >&2.

Обратите внимание, что на самом деле нам не нужно rmцелевой файл, так как перенаправление усекает его. Если бы мы действительно захотели rmего сначала, то вам нужно было бы проверить, является ли это каталогом, и если это так, поместить вместо этого целевой файл в этот каталог, точно так же, как cpделать. Это делает это, но все еще без явногоrm:

cp () {
    target="$2"
    if [ -d "$target" ]; then
        target="$target/$1"
    fi

    if [ -d "$target" ]; then
        printf '"%s": is a directory\n' "$target" >&2
        return 1
    fi

    if [ -e "$target" ]; then
        printf '"%s" exists, overwrite (y/n): ' "$target" >&2
        read
        case "$REPLY" in
            n*|N*) return ;;
        esac
    fi

    cat "$1" >"$target"
}

Вы также можете убедиться, что источник действительно существует, а это то, чтоcpдействительно делает(catтоже, так что его можно полностью исключить, конечно, но это создаст пустой целевой файл):

cp () {
    if [ ! -f "$1" ]; then
        printf '"%s": no such file\n' "$1" >&2
        return 1
    fi

    target="$2"
    if [ -d "$target" ]; then
        target="$target/$1"
    fi

    if [ -d "$target" ]; then
        printf '"%s": is a directory\n' "$target" >&2
        return 1
    fi

    if [ -e "$target" ]; then
        printf '"%s" exists, overwrite (y/n): ' "$target" >&2
        read
        case "$REPLY" in
            n*|N*) return ;;
        esac
    fi

    cat "$1" >"$target"
}

Эта функция не использует "башизмы" и должна работать во всехsh-подобных оболочках.

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

cp () {
    local interactive=0

    # Handle the optional -i flag
    case "$1" in
        -i) interactive=1
            shift ;;
    esac

    # All command line arguments (not -i)
    local -a argv=( "$@" )

    # The target is at the end of argv, pull it off from there
    local target="${argv[-1]}"
    unset argv[-1]

    # Get the source file names
    local -a sources=( "${argv[@]}" )

    for source in "${sources[@]}"; do
        # Skip source files that do not exist
        if [ ! -f "$source" ]; then
            printf '"%s": no such file\n' "$source" >&2
            continue
        fi

        local _target="$target"

        if [ -d "$_target" ]; then
            # Target is a directory, put file inside
            _target="$_target/$source"
        elif (( ${#sources[@]} > 1 )); then
            # More than one source, target needs to be a directory
            printf '"%s": not a directory\n' "$target" >&2
            return 1
        fi

        if [ -d "$_target" ]; then
            # Target can not be overwritten, is directory
            printf '"%s": is a directory\n' "$_target" >&2
            continue
        fi

        if [ "$source" -ef "$_target" ]; then
            printf '"%s" and "%s" are the same file\n' "$source" "$_target" >&2
            continue
        fi

        if [ -e "$_target" ] && (( interactive )); then
            # Prompt user for overwriting target file
            printf '"%s" exists, overwrite (y/n): ' "$_target" >&2
            read
            case "$REPLY" in
                n*|N*) continue ;;
            esac
        fi

        cat -- "$source" >"$_target"
    done
}

В вашем коде неправильные интервалы вif [... ](нужны пробелы до и после [и до]). Вы также не должны пытаться перенаправить тест на /dev/null, так как сам тест не имеет вывода. Кроме того, первый тест должен использовать позиционный параметр $2, а не строку file.

Используя case... esac, как я, вы избегаете необходимости переводить ответ пользователя с помощью trв нижний/верхний регистр. В bash, если бы вы все равно хотели это сделать, более дешевым способом было бы использоватьREPLY="${REPLY^^}"(для верхнего регистра )илиREPLY="${REPLY,,}"(для нижнего регистра ).

Если пользователь говорит "да", с вашим кодом функция помещает имя файла целевого файла в целевой файл.Это не копирование исходного файла. Он должен провалиться до фактического бита копирования функции.

Бит копирования — это то, что вы реализовали с помощью конвейера. Конвейер используется для передачи данных с вывода одной команды на ввод другой команды. Это не то, что нам нужно делать здесь. Просто вызовите catв исходном файле и перенаправьте его вывод в целевой файл.

То же самое не так с вашим звонком trранее. readустанавливает значение переменной, но не производит никакого вывода, поэтому передача readчему-либо бессмысленна.

Явный выход не требуется, если только пользователь не скажет «нет» (или функция не обнаружит какое-либо состояние ошибки, как в битах моего кода, но поскольку это функция, я использую return, а неexit).

Кроме того, вы сказали «функция», но ваша реализация — это скрипт.

Взгляните на https://www.shellcheck.net/, это хороший инструмент для выявления проблемных фрагментов сценариев оболочки.


Использование cat— это всего лишь один способ копирования содержимого файла. Другие способы включают

  • dd if="$1" of="$2" 2>/dev/null
  • Использование любого фильтра -, например утилиты, которую можно заставить просто передавать данные, например. sed "" "$1" >"2"или awk '1' "$1" >"$2"или tr '.' '.' <"$1" >"$2"и т. д.
  • и т. д.

Хитрость заключается в том, чтобы заставить функцию копировать метаданные (права собственности и разрешения )из источника в цель.

Следует также отметить, что функция, которую я написал, будет вести себя совершенно иначе, чем cp, если целью является что-то вроде /dev/tty, например (не -обычный файл ).

4
27.12.2017, 20:19
0 ответов

Теги

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