如何通过bash脚本交换偶数行和奇数行?

发布于 2025-01-10 21:33:45 字数 216 浏览 0 评论 0 原文

在来自标准输入的传入字符串流中,交换偶数行和奇数行。 我尝试这样做,但是从文件读取和 $i -lt $a.count 不起作用:

$a= gc test.txt
for($i=0;$i -lt $a.count;$i++)
{
if($i%2)
{
$a[$i-1]
}
else
{
$a[$i+1]
}
}

请帮助我让它工作

In the incoming string stream from the standard input, swap the even and odd lines.
I've tried to do it like this, but reading from file and $i -lt $a.count aren't working:

$a= gc test.txt
for($i=0;$i -lt $a.count;$i++)
{
if($i%2)
{
$a[$i-1]
}
else
{
$a[$i+1]
}
}

Please, help me to get this working

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

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

发布评论

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

评论(2

北斗星光 2025-01-17 21:33:45

建议一行 awk 脚本:

awk '!(NR%2){print$0;print r}NR%2{r=$0}' input.txt

awk 脚本说明

!(NR % 2){ # if row number divide by 2 witout reminder
  print $0; # print current row
  print evenRow; # print saved row
}
(NR % 2){ # if row number divided by 2 with reminder
  evenRow = $0; # save current row in variable
}

Suggesting one line awk script:

awk '!(NR%2){print$0;print r}NR%2{r=$0}' input.txt

awk script explanation

!(NR % 2){ # if row number divide by 2 witout reminder
  print $0; # print current row
  print evenRow; # print saved row
}
(NR % 2){ # if row number divided by 2 with reminder
  evenRow = $0; # save current row in variable
}
爱格式化 2025-01-17 21:33:45

这里已经有一个很好的基于 awk 的答案,并且在 sed 和 awk 解决方案="https://www.theunixschool.com/2012/06/swap-every-2-lines-in-file.html" rel="nofollow noreferrer">在文件中每 2 行交换。然而,中的shell解决方案每2行交换一次在文件中几乎是可笑的无能。下面的代码是对功能正确的纯 Bash 解决方案的尝试。 Bash 非常慢,因此只适用于小文件(可能最多 10,000 行)。

#! /bin/bash -p

idx=0 lines=()
while IFS= read -r 'lines[idx]' || [[ -n ${lines[idx]} ]]; do
    (( idx == 1 )) && printf '%s\n%s\n' "${lines[1]}" "${lines[0]}"
    idx=$(( (idx+1)%2 ))
done
(( idx == 1 )) && printf '%s\n' "${lines[0]}"
  • lines 数组用于保存两个连续的行。
  • IFS= 防止在读取行时删除空格。
  • idx 变量循环 0, 1, 0, 1, ... (idx=$(( (idx+1)%2 )) code>),因此读取 lines[idx] 时会循环将输入行置于 lines0 和 1 处> 数组。
  • 如果 read 函数在输入中遇到未终止的最后一行,则立即返回非零状态。这可能会导致循环在处理最后一行之前终止,从而在输出中丢失它。 <代码>|| [[ -n ${lines[idx]} ]] 通过检查 read 是否实际读取了某些输入来避免这种情况。 (幸运的是,文件末尾不存在未终止的空行。)
  • 使用 printf 而不是 echo 来输出行,因为 echo< /code> 对于任意字符串不能可靠地工作。 (例如,仅包含 -n 的行将因 echo "$line" 而完全丢失。)请参阅 为什么 printf 比 echo 更好?
  • 该问题没有说明如果输入的行数为奇数该怎么办。此代码 ((( idx == 1 )) && printf '%s\n' "${lines[0]}") 只是传递交换行之后的最后一行。其他合理的选择是删除最后一行或在其前面添加一个额外的空行。如果需要,可以轻松修改代码以执行其中一项操作。
  • 代码是 Shellcheck-clean。

There's already a good awk-based answer to the question here, and there are a few decent-looking sed and awk solutions in Swap every 2 lines in a file. However, the shell solution in Swap every 2 lines in a file is almost comically incompetent. The code below is an attempt at a functionally correct pure Bash solution. Bash is very slow, so it is practical to use only on small files (maybe up to 10 thousand lines).

#! /bin/bash -p

idx=0 lines=()
while IFS= read -r 'lines[idx]' || [[ -n ${lines[idx]} ]]; do
    (( idx == 1 )) && printf '%s\n%s\n' "${lines[1]}" "${lines[0]}"
    idx=$(( (idx+1)%2 ))
done
(( idx == 1 )) && printf '%s\n' "${lines[0]}"
  • The lines array is used to hold two consecutive lines.
  • IFS= prevents whitespace being stripped as lines are read.
  • The idx variable cycles through 0, 1, 0, 1, ... (idx=$(( (idx+1)%2 ))) so reading to lines[idx] cycles through putting input lines at indexes 0 and 1 in the lines array.
  • The read function returns non-zero status immediately if it encounters an unterminated final line in the input. That could cause the loop to terminate before processing the last line, thus losing it in the output. The || [[ -n ${lines[idx]} ]] avoids that by checking if the read actually read some input. (Fortunately, there's no such thing as an unterminated empty line at the end of a file.)
  • printf is used instead of echo to output the lines because echo doesn't work reliably for arbitrary strings. (For instance, a line containing just -n would get lost completely by echo "$line".) See Why is printf better than echo?.
  • The question doesn't say what to do if the input has an odd number of lines. This code ((( idx == 1 )) && printf '%s\n' "${lines[0]}") just passes the last line through, after the swapped lines. Other reasonable options would be to drop the last line or print it preceded by an extra blank line. The code can easily be modified to do one of those if desired.
  • The code is Shellcheck-clean.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文