bash脚本新手。我很熟悉shell脚本。我为客户端编写了这个文本转换脚本。并提取我想要的网址和文章标题。真棒。
echo $(var=$(curl -L website.com/news)) |
grep -Po '<h3 class="article-link"><a href="\K[^<]+' <<< $var |
result=$(sed 's/"/\n/g' | sed 's/ \//\n\//g' | sed 's/>//g') ; let this=0 ; echo "$result" | while read line ; do if ((this % 2 == 0 )) ; then echo website.com/news$line ; else echo $line ; fi ; let this+=1 ; done
当我尝试将其提取到文件并使用bash或sh myThing.sh运行时,它根本不起作用。唯一回应的是&#39; webiste.com/news' ;,当我试图回应$ this时,我得到的只是1.我做错了什么?
#!/bin/bash
echo $(var=$(curl -L website.com/news)) |
grep -Po '<h3 class="article-link"><a href="\K[^<]+' <<< $var |
result=$(sed 's/"/\n/g' | sed 's/ \//\n\//g' | sed 's/>//g')
let this=0
echo "$result" | while read line
do
if ((this % 2 == 0 ))
then
echo website.com/news$line
else
echo $line
fi
let this+=1
done
编辑:
#!/bin/bash
var=$(curl -L linux.com/news)
select=$(grep -Po '<h3 class="article-list__title"><a href="\K[^<]+' <<< $var)
result=$(sed 's/"/\n/g' | sed 's/ \//\n\//g' | sed 's/>//g')
let this=0
echo "$result" | while read line
do
if ((this % 2 == 0 ))
then
echo website.com/news$line
else
echo $line
fi
let this+=1
done
答案 0 :(得分:3)
这个答案解决了OP的特定问题,但解决了问题&#34;为什么我的shell命令在提示符下工作,但不是一个bash脚本?&#34; 一般 ,Etan Reisner在评论中提供了一个很好的答案:
&#34;你要么没有运行那个确切的命令,要么&#34;工作&#34;因为你的贝壳状态会以你所采取的方式影响事物的工作&#34;并且你的脚本没有那种状态。尝试启动一个全新的shell会话,看看该命令本身是否适用于你。&#34;
echo $(var=...)
会为变量$var
分配值,但不会输出任何内容,因此echo
命令只会打印换行符。
此外,因为$var
的赋值发生在$(...)
内(命令替换),所以它被限制在 subshell 中,替换中的命令会进入,所以$var
将不在调用shell中定义
(子shell是子进程,其中包含当前shell环境的重复,但无法修改当前shell& #39;环境)。
更一般地说,你无法在管道中有意义地定义变量 - 它们既不会对其他管道段可见,也不会在管道完成后显示。 [1 ]
您的[原始]命令可能有效的唯一原因是$var
在您的shell中有预先存在的值 。
事实上,假设您通过here-string(grep
)向<<<
提供输入,管道的第一段(echo ...
)完全被忽略< / em>的强>
要将curl
的输出通过管道传递到grep
然后传递到sed
,根本不需要任何中间变量。
此外,您的sed
命令缺少输入:您可能打算在第一次尝试时提供$var
,在第二次尝试时提供$select
(您的第二次尝试来了)接近正确的解决方案)。
你最终可能会寻找什么:
result=$(curl -L website.com/news |
grep -Po '<h3 class="article-link"><a href="\K[^<]+' |
sed 's/"/\n/g' | sed 's/ \//\n\//g' | sed 's/>//g')
# ... processing of "$result"
一些补充说明:
sed
来电合并为一个。while
循环,而无需中间变量$result
。"$line"
而不是$line
来保护它们免受shell的解释(分词,通配)。 let this+=1
在现代Bash中更好地表达为(( ++this ))
。bash
。 [1]默认情况下,管道中涉及的所有命令都在bash
的子shell 中运行,因此它们都会看到副本父 shell变量的。 Bash 4.2+提供lastpipe
选项(默认情况下关闭),允许您通过运行<在当前 shell而不是子shell 中创建变量当前shell而不是子shell中的em> last 管道段(仅限),以便在管道完成后继续存在... | while read -r line ...
和$line
等场景。
请注意,这仍然无法在较早的管道段中定义变量,希望以后的段会看到它 - 这可能从不工作,因为构成管道的命令是同时启动 ,只有通过协调输入和输出流才能实现有效的从左到右处理。
答案 1 :(得分:1)
这条线完全错了。你试图通过管道传递每个进程的标准输出,当它们都没有打印出除标准错误之外的任何东西。
echo $(var=$(curl -L website.com/news)) | grep -Po '<h3 class="article-link"><a href="\K[^<]+' <<< $var | result=$(sed 's/"/\n/g' | sed 's/ \//\n\//g' | sed 's/>//g')
我会打破我认为你试图做的事情。
echo $(var=$(curl -: website.com/news))
上面的代码只会打印标准错误,这是一个独立的流而不是标准输出。标准输出分配给$var
。但是,您试图将标准输出传递给下一个进程,此时此过程只是一个换行符。
grep -Po '<h3 class="article-link"><a href="\K[^<]+' <<< $var
here-string <<<
优先于管道。但变量$var
会丢失,因为它是在子shell中定义的,而不是在父shell中定义的。感谢@mklement0。
完成所有这些的正确方法是不使用$var
。您想要的只是$result
中存储的值。
result=$(curl -L website.com/news | grep -Po '<h3 class="article-link"><a href="\K[^<]+'| sed 's/"/\n/g' | sed 's/ \//\n\//g' | sed 's/>//g')
我不打算优化您的脚本。这是一个建议的解决方案。对您的问题的更全面的回答为什么我的shell命令在提示符下工作,而不是作为bash脚本?由mklement0 here回答。