我正在尝试创建一个Bash脚本,它将从命令行提供的最后一个参数提取到一个变量中,以便在别处使用。这是我正在处理的脚本:
#!/bin/bash
# compact - archive and compact file/folder(s)
eval LAST=\$$#
FILES="$@"
NAME=$LAST
# Usage - display usage if no parameters are given
if [[ -z $NAME ]]; then
echo "compact <file> <folder>... <compressed-name>.tar.gz"
exit
fi
# Check if an archive name has been given
if [[ -f $NAME ]]; then
echo "File exists or you forgot to enter a filename. Exiting."
exit
fi
tar -czvpf "$NAME".tar.gz $FILES
由于第一个参数可以是任何数字,我必须找到一种方法来提取最后一个参数,(例如压缩文件.a file.b file.d files-a-b-d.tar.gz)。现在,存档名称将包含在要压缩的文件中。有没有办法做到这一点?
答案 0 :(得分:88)
要从数组中删除最后一项,您可以使用以下内容:
#!/bin/bash
length=$(($#-1))
array=${@:1:$length}
echo $array
更短的方式:
array=${@:1:$#-1}
但是arays是Bashism,请尽量避免使用它们:(。
答案 1 :(得分:19)
last_arg="${!#}"
答案 2 :(得分:11)
已经发布了几种解决方案;但是,我建议重组您的脚本,以便存档名称是第一个参数而不是最后一个。然后它非常简单,因为您可以使用shift
builtin删除第一个参数:
ARCHIVENAME="$1"
shift
# Now "$@" contains all of the arguments except for the first
答案 3 :(得分:10)
这就是我在脚本中的行为
last=${@:$#} # last parameter
other=${*%${!#}} # all parameters except the last
修改强>
根据一些评论(见下文),这种解决方案比其他解决方案更便携
请阅读Michael Dimmitt的评论,了解其工作原理。
答案 4 :(得分:5)
谢谢你们,完成了它,继续最后的bash脚本:
#!/bin/bash
# compact - archive and compress file/folder(s)
# Extract archive filename for variable
ARCHIVENAME="${!#}"
# Remove archive filename for file/folder list to backup
length=$(($#-1))
FILES=${@:1:$length}
# Usage - display usage if no parameters are given
if [[ -z $@ ]]; then
echo "compact <file> <folder>... <compressed-name>.tar.gz"
exit
fi
# Tar the files, name archive after last file/folder if no name given
if [[ ! -f $ARCHIVENAME ]]; then
tar -czvpf "$ARCHIVENAME".tar.gz $FILES; else
tar -czvpf "$ARCHIVENAME".tar.gz "$@"
fi
答案 5 :(得分:3)
删除Krzysztof Klimonda解决方案中使用的length
变量:
(
set -- 1 2 3 4 5
echo "${@:1:($#-1)}" # 1 2 3 4
echo "${@:(-$#):($#-1)}" # 1 2 3 4
)
答案 6 :(得分:3)
我会将此作为评论添加,但没有足够的声誉,无论如何答案都要长一点。希望它不介意。
正如@func所说:
说明:last_arg = “$ {!#}”
工作原理:
$ {!PARAM} 表示间接级别。您没有引用 PARAM 本身,而是存储在 PARAM 中的值(将 PARAM 视为指向值的指针)。
$ {#} 扩展为参数数量(注意: $ 0 - 脚本名称 - 此处不计算在内)。
考虑执行以下事项:
$./myscript.sh p1 p2 p3
在myscript.sh中
#!/bin/bash
echo "Number of params: ${#}" # 3
echo "Last parameter using '\${!#}': ${!#}" # p3
echo "Last parameter by evaluating positional value: $(eval LASTP='$'${#} ; echo $LASTP)" # p3
因此,您可以将 $ {!#} 视为上述eval用法的快捷方式,它完全符合上述方法 - 评估存储在给定参数中的值,此处参数为 3 并保持位置参数 $ 3
现在,如果您想要除最后一个之外的所有参数,您可以使用子字符串删除 $ {PARAM%PATTERN} ,其中%符号表示'删除字符串'末尾的最短匹配模式。
因此在我们的剧本中:
echo "Every parameter except the last one: ${*%${!#}}"
您可以在此处阅读:Parameter expansion
答案 7 :(得分:1)
#!/bin/bash
lastidx=$#
lastidx=`expr $lastidx - 1`
eval last='$'{$lastidx}
echo $last
答案 8 :(得分:1)
尝试:
if [ "$#" -gt '0' ]; then
/bin/echo "${!#}" "${@:1:$(($# - 1))}
fi
答案 9 :(得分:1)
你确定这个花哨的脚本比tar的简单别名更好吗?
alias compact="tar -czvpf"
用法是:
compact ARCHIVENAME FILES...
FILES可以是file1 file2
,也可以是*.html
答案 10 :(得分:1)
答案 11 :(得分:1)
从参数列表中拉出最后一个参数的替代方法:
eval last="\$$#"
eval set -- `awk 'BEGIN{for(i=1;i<'$#';i++) printf " \"$%d\"",i;}'`
答案 12 :(得分:0)
#!/bin/sh eval last='$'$# while test $# -gt 1; do list="$list $1" shift done echo $list $last
答案 13 :(得分:0)
我找不到在$@
上使用array-subscript表示法的方法,所以这是我能做的最好的事情:
#!/bin/bash
args=("$@")
echo "${args[$(($#-1))]}"
答案 14 :(得分:0)
此脚本可能适合您 - 它返回参数的子范围,可以从另一个脚本调用。
$ args_get_range 2 -2 y a b "c 1" d e f g
'b' 'c 1' 'd' 'e'
$ args_get_range 1 2 n arg1 arg2
arg1 arg2
$ args_get_range 2 -2 y arg1 arg2 arg3 "arg 4" arg5
'arg2' 'arg3'
$ args_get_range 2 -1 y arg1 arg2 arg3 "arg 4" arg5
'arg2' 'arg3' 'arg 4'
# You could use this in another script of course
# by calling it like so, which puts all
# args except the last one into a new variable
# called NEW_ARGS
NEW_ARGS=$(args_get_range 1 -1 y "$@")
#!/usr/bin/env bash
function show_help()
{
IT="
Extracts a range of arguments from passed in args
and returns them quoted or not quoted.
usage: START END QUOTED ARG1 {ARG2} ...
e.g.
# extract args 2-3
$ args_get_range.sh 2 3 n arg1 arg2 arg3
arg2 arg3
# extract all args from 2 to one before the last argument
$ args_get_range.sh 2 -1 n arg1 arg2 arg3 arg4 arg5
arg2 arg3 arg4
# extract all args from 2 to 3, quoting them in the response
$ args_get_range.sh 2 3 y arg1 arg2 arg3 arg4 arg5
'arg2' 'arg3'
# You could use this in another script of course
# by calling it like so, which puts all
# args except the last one into a new variable
# called NEW_ARGS
NEW_ARGS=\$(args_get_range.sh 1 -1 \"\$@\")
"
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ $# -lt 3 ]
then
show_help
fi
START=$1
END=$2
QUOTED=$3
shift;
shift;
shift;
if [ $# -eq 0 ]
then
echo "Please supply a folder name"
exit;
fi
# If end is a negative, it means relative
# to the last argument.
if [ $END -lt 0 ]
then
END=$(($#+$END))
fi
ARGS=""
COUNT=$(($START-1))
for i in "${@:$START}"
do
COUNT=$((COUNT+1))
if [ "$QUOTED" == "y" ]
then
ARGS="$ARGS '$i'"
else
ARGS="$ARGS $i"
fi
if [ $COUNT -eq $END ]
then
echo $ARGS
exit;
fi
done
echo $ARGS