如何在 bash/zsh/ksh 中复制期间创建目录?
-
13-09-2019 - |
题
我经常收到以下消息,例如将开发文件复制到主分支时
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
问题
- 要更改警告消息: 哪个文件控制“没有这样的文件或目录”命令?
- 抓取初始命令中的路径和没有文件的 mkidr 路径:如何在初始命令中抓取路径?
- 要使用您选择的语言(例如 AWK)从末尾开始抓取: 当 / 是字段分隔符时,如何删除路径中的最后一个匹配项? 我不知道如何使用 AWK 从末尾开始抓取字母。
解决方案
这是我编写的一个函数,可以在 zsh、bash 或 ksh 中运行。
笔记: 它启用了调试(它回显将运行的命令而不是执行它们)。如果您注释掉该行,它实际上会运行它们。
警告: 它还没有经过彻底的测试。
要使用它,请将此脚本放入名为的文件中 cpmd
在 /usr/local/bin
(或您路径中的其他地方)。要激活它,请在 shell 提示符下键入以下命令(或将其添加到启动脚本中 - 对于 bash,它将是 ~/.bashrc
):
source cpmd
然后您可以使用如下命令复制文件:
cpmd carparts /home/dave/Documents/nonexistent/newdir/
目录“不存在”或“newdir”都不存在。创建两个目录,然后将名为“carparts”的文件复制到“newdir”。
如果末尾不包含斜杠(“/”),则最后一部分将被视为文件名,并且之前的任何不存在的目录都会被创建:
cpmd supplies /home/dave/Documents/anothernew/consumables
创建目录“anothernew”,然后使用新文件名“consumables”复制“supplies”。
如果目标中的所有目录都已存在, 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
}
其他提示
该错误消息来自 cp
命令,而不是 zsh。如果您想改进输出,则必须编写用于截断和检查路径的逻辑,并检查它是否存在。
有一些命令可以帮助完成此操作,请查看 basename(1) 和 dirname(1)。
不隶属于 StackOverflow