我有一个文件links.txt:
1 a.sh
3 b.sh
6 c.sh
4 d.sh
因此,如果我将1,4作为参数传递给另一个文件(master.sh),则应将a.sh和d.sh存储在变量中。
答案 0 :(得分:2)
sed '3!d'
会打印第3行,但不会打印以3
开头的行。为此,您需要sed '/^3 /!d'
。问题是你无法将它们组合成更多行,因为这意味着“删除所有不以3开头的内容”,这意味着所有其他行都将被遗漏。因此,请改用sed -n '/^3 /p'
,即默认情况下不打印并告诉sed要打印的行,而不是要删除的行。
你可以遍历参数并从它们创建一个打印行的sed脚本,然后使用这个输出运行sed
:
#!/bin/bash
file=$1
shift
for id in "$@" ; do
echo "/^$id /p"
done | sed -nf- "$file"
以script.sh filename 3 4
运行。
如果要从输出中删除id,可以使用
cut -f2 -d' '
或者您可以修改生成的sed脚本来执行工作
echo "/^$id /s/.* //p"
即。仅在替换成功时打印。
答案 1 :(得分:1)
这会循环遍历每个参数并在链接文件中为它进行greps。结果通过管道传输到cut中,我们将分隔符指定为带-d标志的空格,使用-f标志将字段编号指定为2。最后,这将附加到名为files的数组中。
links="links.txt"
files=()
for arg in $@; do
files=("${files[@]}" `grep "^$arg" "$links" | cut -d" " -f2`)
done;
echo ${files[@]}
用法:
$ ./master.sh 1 4
a.sh d.sh
编辑: 正如mklement0所指出的,上面的解决方案每个arg读取一次文件。下面首先构建模式,然后只读取一次文件。
links="links.txt"
pattern="^$1\s"
for arg in ${@:2}; do
pattern+="|^$arg\s"
done
files=$(grep -E "$pattern" "$links" | cut -d" " -f2)
echo ${files[@]}
用法:
$ ./master.sh 1 4
a.sh d.sh
答案 2 :(得分:0)
以下 awk
解决方案:
保留参数顺序;也就是说,结果反映了指定查找值的顺序(与文件中发生查找值的顺序相反)。
readarray
技术可以与这个单行结合,这是一个通用的Panta's answer的变体:grep -f <(printf "^%s\n" "$@") links.txt | cut -d' ' -f2-
表现良好,因为输入文件只能读取一次;唯一的要求是所有键值对都作为一个整体适合内存(作为单个关联的Awk数组(字典))。
适用于没有嵌入空格的任何查找值。
a.sh
等值)没有嵌入的空格。 awk
无法很好地处理引用字段,因此需要更多工作。#!/bin/bash
readarray -t files < <(
awk -v idList="$*" '
BEGIN { count=split(idList, idArr); for (i in idArr) idDict[idArr[i]]++ }
$1 in idDict { idDict[$1] = $2 }
END { for (i=1; i<=count; ++i) print idDict[idArr[i]] }
' links.txt
)
# Print results.
printf '%s\n' "${files[@]}"
readarray -t files
将stdin输入(<
)逐行读入数组变量files
。
readarray
需要Bash v4 +;在Bash 3.x上,例如在macOS上,用。替换此部分
IFS=$'\n' read -d '' -ra files
<(...)
是一个Bash process substitution,从松散的角度来说,它提供了封闭命令的输出,就好像它是(自行删除)临时文件一样。
readarray
在当前shell 中运行(与子shell 相反,如果已使用管道),这对于files
变量保留在脚本的其余部分中。 awk
命令按如下方式分解:
-v idList="$*"
将所有命令行参数的空格分隔列表作为单个字符串传递给 Awk 变量idList
。
BEGIN { ... }
仅在处理各行之前执行
split(idList, idArr)
按空格将输入ID列表拆分为数组,并将结果存储在idArr
中。
for (i in idArr) idDict[idArr[i]]++ }
然后将(概念上常规的)数组转换为 associative 数组idDict
(字典),其键是输入ID - 这样可以通过ID稍后,还允许为每个ID存储查找结果。
$1 in idDict { idDict[$1] = $2 }
:
$1 in idDict
) - 例如$1
- 是关联数组的键(6
),则模式in
返回true {1}},如果是,则执行关联的操作(idDict
)。{...}
然后将第二个字段({ idDict[$1] = $2 }
) - 例如$2
- 分配给密钥c.sh
的{{1}}条目。 iDict
执行一次, 后处理所有输入行:
$1
按顺序循环遍历所有输入ID 并打印每个ID的查找结果,即具有该ID的字典条目的值。答案 3 :(得分:0)
以下是grep和cut的另一个例子:
#!/bin/bash
for line in $(grep "$1\|$2" links.txt|cut -d' ' -f2)
do
echo $line
done
使用示例:
./master.sh 1 4
a.sh
d.sh
答案 4 :(得分:0)
为什么不只是存储值并随意调用它们:
items=()
while read -r num file
do
items[num]="$file"
done<links.txt
for arg
do
echo "${items[arg]}"
done
现在您可以随时使用items数组:)