如何在 bash/zsh/ksh 中复制期间创建目录?

发布于 2024-07-23 11:03:03 字数 765 浏览 7 评论 0原文

我经常收到以下消息,例如,当将开发文件复制到主分支时,

cp: /Users/Masi/gitHub/shells/zsh/dvorak: No such file or directory
cp: /Users/Masi/gitHub/shells/zsh/dvorak2: No such file or directory

我想询问有关给定文件夹的创建的信息,这样如果我对问题回答“是”,我的初始命令将运行。

当我尝试将文件复制到不存在的目录时,我尝试使用伪代码

if no such a directory exists, then asks users about to create it:
   if yes, then mkdir directory AND run the initial command again
   else do noting

问题

  1. 要更改警告消息:文件确实控制“没有这样的文件或目录”命令吗?
  2. 要抓取初始命令中的路径和没有文件的 mkidr 路径:如何抓取初始命令中的路径?
  3. 使用您选择的语言(例如 AWK)从末尾开始抓取:当 / 是字段分隔符时,您将如何删除路径中的最后一个匹配项? 我不确定如何使用 AWK 从末尾开始抓取字母。

I get the following messages often, for instance when coping dev files to a master branch

cp: /Users/Masi/gitHub/shells/zsh/dvorak: No such file or directory
cp: /Users/Masi/gitHub/shells/zsh/dvorak2: No such file or directory

I would like to be asked about the creation of the given folders such that my initial command will be run if I answer yes to the question(s).

My attempt in pseudo-code when I am trying to copy a file to a directory which does not exists

if no such a directory exists, then asks users about to create it:
   if yes, then mkdir directory AND run the initial command again
   else do noting

Problems

  1. To change the warning message: Which file does control the "No such file or directory" -command?
  2. To scrape the Path in the initial command AND mkidr Path without the file: How would scrape the Path in the initial command?
  3. To scrape from the end with your chosen language such as AWK: How would you remove the last match in the Path when / is the field separator? I am not sure how you can scrape letters starting from the end with AWK.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

徒留西风 2024-07-30 11:03:03

这是我编写的一个函数,可以在 zsh、bash 或 ksh 中运行。

注意: 它启用了调试(它回显将运行的命令,而不是执行它们)。 如果您注释掉该行,它实际上会运行它们。

警告它尚未经过彻底测试。

要使用它,请将此脚本放入/usr/local/bin(或路径中的其他位置)中名为 cpmd 的文件。 要激活它,请在 shell 提示符下键入以下命令(或将其添加到启动脚本中 - 对于 bash,它是 ~/.bashrc):

source cpmd

然后您可以使用如下命令复制文件:

cpmd carparts /home/dave/Documents/nonexistent/newdir/

目录“不存在”或“newdir”都不存在。 创建两个目录,然后将名为“carparts”的文件复制到“newdir”。

如果末尾不包含斜杠(“/”),最后一部分将被视为文件名,并创建之前不存在的目录:

cpmd supplies /home/dave/Documents/anothernew/consumables

创建目录“anothernew”,然后复制“supplies”新文件名为“consumables”。

如果目标中的所有目录均已存在,cpmd 的作用类似于常规 cp 命令。

function cpmd {
    # copies files and makes intermediate dest. directories if they don't exist
    # for bash, ksh or zsh
    # by Dennis Williamson - 2009-06-14
    # http://stackoverflow.com/questions/993266/unable-to-make-nosuchdirectory-message-useful-in-zsh

    # WARNING: no validation is performed on $1 and $2

    # all cp commands below are hardcoded with -i (interactive) to prevent overwriting

   if [[ -n $KSH_VERSION ]]
   then
       alias local=typeset
       local func="$0"
       local lastchar="${2: -1}"
       readcmd () { read "$2?$1"; }
    elif [[ -n $ZSH_VERSION ]]
    then
        local func="$0"
        # the following two lines are split up instead of doing "${2[-1]}"
        # to keep ksh from complaining when the function is loaded
        local dest="$2"
        local lastchar="${dest[-1]}"
        readcmd () { read "$2?$1"; }
    elif [[ -n $BASH_VERSION ]]
    then
    local func="$FUNCNAME"
        local lastchar="${2:(-1)}"
        readcmd () { read -p "$1" $2; }
    else
        echo "cpmd has only been tested in bash, ksh and zsh." >&2
        return 1
    fi

    local DEBUG='echo' # COMMENT THIS OUT to make this function actually work

    if [[ ${#@} != 2 ]]
    then
        echo "$func: invalid number of parameters
Usage:
  $func source destination

  where 'destination' can include nonexistent directories (which will
  be created). You must end 'destination' with a / in order for it to
  specify only directories. Without the final slash, the 'source' will
  be copied with a new name (the last portion of 'destination'). If you
  are copying multiple files and 'destination' is not a directory, the
  copy will fail." >&2
        return 1
    fi

    local dir=$(dirname "$2")
    local response
    local nl=
\n'

    # destination ($2) is presumed to be in one of the following formats:
    # .../existdir              test 1  (-d "$2")
    # .../existdir/existfile    test 2  (-f "$2")
    # .../existdir/newfile      test 3  (-d "$dir" && $lastchar != '/')
    # .../existdir/newdir/      (else)
    # .../newdir/newdir/        (else)
    # .../newdir/newfile        (else)

    if [[ -d "$2" || -f "$2" || (-d "$dir" && $lastchar != '/') ]]
    then
        $DEBUG cp -i "$1" "$2"
    else
        if [[ $lastchar == '/' ]]
        then
            dir="$2"
        fi
        local prompt="$func: The destination directory...${nl}  ${dir}${nl}...does not exist. Create? (y/n): "
        while [[ -z $response ]]
        do
            readcmd "$prompt" response
            case $response in
                y|Y) response="Y" ;;
                n|N) ;;
                *) response=
                   prompt="$func: Invalid response.${nl}  Create destination directory? (y/n): ";;
            esac
        done
        if [[ $response == "Y" ]]
        then
            $DEBUG mkdir -p "$dir" && $DEBUG cp -i "$1" "$2"
        else
            echo "$func: Cancelled." >&2
        fi
    fi
}

Here is a function I wrote which will work in zsh, bash or ksh.

Note: It has debugging enabled (it echoes the commands it would run rather than executing them). If you comment out that line, it will actually run them.

Caution: It hasn't been thoroughly tested.

To use it, put this script in a file called cpmd in /usr/local/bin (or elsewhere in your path). To activate it, from the shell prompt type the following command (or add it to your startup script - for bash it would be ~/.bashrc):

source cpmd

Then you can copy a file using a command like this:

cpmd carparts /home/dave/Documents/nonexistent/newdir/

Neither directory "nonexistent" or "newdir" exist yet. Both directories are created then the file named "carparts" is copied to "newdir".

If you don't include a slash ("/") at the end, the last part is treated as a file name and any non-existent directories before that are created:

cpmd supplies /home/dave/Documents/anothernew/consumables

The directory "anothernew" is created then "supplies" is copied with the new filename "consumables".

If all the directories in the destination already exist, cpmd acts like the regular cp command.

function cpmd {
    # copies files and makes intermediate dest. directories if they don't exist
    # for bash, ksh or zsh
    # by Dennis Williamson - 2009-06-14
    # http://stackoverflow.com/questions/993266/unable-to-make-nosuchdirectory-message-useful-in-zsh

    # WARNING: no validation is performed on $1 and $2

    # all cp commands below are hardcoded with -i (interactive) to prevent overwriting

   if [[ -n $KSH_VERSION ]]
   then
       alias local=typeset
       local func="$0"
       local lastchar="${2: -1}"
       readcmd () { read "$2?$1"; }
    elif [[ -n $ZSH_VERSION ]]
    then
        local func="$0"
        # the following two lines are split up instead of doing "${2[-1]}"
        # to keep ksh from complaining when the function is loaded
        local dest="$2"
        local lastchar="${dest[-1]}"
        readcmd () { read "$2?$1"; }
    elif [[ -n $BASH_VERSION ]]
    then
    local func="$FUNCNAME"
        local lastchar="${2:(-1)}"
        readcmd () { read -p "$1" $2; }
    else
        echo "cpmd has only been tested in bash, ksh and zsh." >&2
        return 1
    fi

    local DEBUG='echo' # COMMENT THIS OUT to make this function actually work

    if [[ ${#@} != 2 ]]
    then
        echo "$func: invalid number of parameters
Usage:
  $func source destination

  where 'destination' can include nonexistent directories (which will
  be created). You must end 'destination' with a / in order for it to
  specify only directories. Without the final slash, the 'source' will
  be copied with a new name (the last portion of 'destination'). If you
  are copying multiple files and 'destination' is not a directory, the
  copy will fail." >&2
        return 1
    fi

    local dir=$(dirname "$2")
    local response
    local nl=
\n'

    # destination ($2) is presumed to be in one of the following formats:
    # .../existdir              test 1  (-d "$2")
    # .../existdir/existfile    test 2  (-f "$2")
    # .../existdir/newfile      test 3  (-d "$dir" && $lastchar != '/')
    # .../existdir/newdir/      (else)
    # .../newdir/newdir/        (else)
    # .../newdir/newfile        (else)

    if [[ -d "$2" || -f "$2" || (-d "$dir" && $lastchar != '/') ]]
    then
        $DEBUG cp -i "$1" "$2"
    else
        if [[ $lastchar == '/' ]]
        then
            dir="$2"
        fi
        local prompt="$func: The destination directory...${nl}  ${dir}${nl}...does not exist. Create? (y/n): "
        while [[ -z $response ]]
        do
            readcmd "$prompt" response
            case $response in
                y|Y) response="Y" ;;
                n|N) ;;
                *) response=
                   prompt="$func: Invalid response.${nl}  Create destination directory? (y/n): ";;
            esac
        done
        if [[ $response == "Y" ]]
        then
            $DEBUG mkdir -p "$dir" && $DEBUG cp -i "$1" "$2"
        else
            echo "$func: Cancelled." >&2
        fi
    fi
}
热风软妹 2024-07-30 11:03:03

该错误消息来自 cp 命令,而不是 zsh。 如果您想改进输出,则必须编写用于截断和检查路径的逻辑,并检查它是否存在。

有一些命令可以帮助完成此操作,请查看 basename(1) 和 dirname(1)。

That error message is coming from the cp command, not zsh. If you want to improve the output, you're going to have to write the logic for truncating and examining the path along with checking to see if it exists or not.

There are commands to assist with this, have a look at basename(1) and dirname(1).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文