【问题标题】:Deleting first n rows and column x from multiple files using Bash script使用 Bash 脚本从多个文件中删除前 n 行和第 x 列
【发布时间】:2016-03-20 20:24:03
【问题描述】:

我知道“删除 n 行”和“删除 x 列”问题之前都已单独回答过。我目前的问题是我正在编写我的第一个 bash 脚本,并且无法使该脚本按我想要的方式工作。

file0001.csv(一个文件夹里有几百个这样的文件)

Data number of lines 540
No.,Profile,Unit
1,1027.84,µm
2,1027.92,µm
3,1028,µm
4,1028.81,µm

期望的输出

1,1027.84
2,1027.92
3,1028
4,1028.81

我可以单独使用 sed 和 cut,但由于某种原因,以下 bash 脚本没有考虑 cut。它还给我一个错误“sed:无法读取ls:没有这样的文件或目录”,但sed成功并且输出保存到原始文件中。

sem2csv.sh

for files in 'ls *.csv'  #list of all .csv files
do
  sed '1,2d' -i $files | cut -f  '1-2' -d  ','
done

实际输出:

1,1027.84,µm
2,1027.92,µm
3,1028,µm
4,1028.81,µm

我知道可能有 awk 单行,但我真的很想了解为什么这个特定的 bash 脚本没有按预期运行。我错过了什么?

【问题讨论】:

    标签: bash sed cut


    【解决方案1】:

    sed-i 选项修改文件。您到cut 的管道没有收到任何输入,因为sed -i 没有产生任何输出。如果没有这个选项,sed 会将结果写入标准输出,而不是写回文件,然后你的管道就可以工作了;但是您必须自己将结果写回原始文件。

    此外,单引号会抑制扩展——您正在“循环”单个文字字符串 ls *.csv。您不是quoting it properly 的事实会导致字符串在循环inside 中进行通配符扩展。所以在变量插值之后,你的sed 命令扩展为

    sed -i 1,2d ls *.csv
    

    and then shell 扩展*.csv,因为它没有被引用。 (您应该已经收到警告说当前目录中也没有名为 ls 的文件。)您可能试图复制一个使用反引号 (ASCII 96) 而不是单引号 (ASCII 39) 的示例——差别很大。

    不管怎样,lsuseless——正确的成语是

    for files in *.csv; do
      sed '1,2d' "$files" ...   # the double quotes here are important
    done
    

    混合sedcut 通常不是一个好主意,因为您可以用简单的sed 脚本表达cut 可以做的任何事情。所以你的整个脚本可能是

    for f in *.csv; do
        sed -i -e '1,2d' -e 's/,[^,]*$//' "$f"
    done
    

    表示删除最后一个逗号及其后面的所有内容。 (如果您的sed 不喜欢多个-e 选项,请尝试使用分号分隔符:sed -i '1,2d;s/,[^,]*$//' "$f"

    【讨论】:

    • 感谢您提供这个非常有用的答案,这正是我想知道的。 :D
    • @biohazard 不,不是真的。如果只有一个脚本字符串,-e 是多余的。尽管在 *BSD 上您需要为 -i 提供一个选项——但由于您的示例没有使用该选项,我假设您在另一个不需要这样做的平台上。
    • 一些旧版sed 变体可能存在高位字符问题。在单个文件上尝试 perl -pi 's/,[^,]*$//' file 看看是否有帮助。也许也可以使用您的语言环境设置。
    • 问题解决了!在for 循环内,我先后使用dos2unix "$f" 去掉DOS 回车,iconv -f shift-jis -t utf-8 "$f" -o "$f" 将Shift-JIS 转换为UTF-8(终端终于停止警告我这是一个二进制文件并正确显示μ),最后是sed -i '1,2d;s/,[^,]*$//' "$f"。再次感谢您的帮助!
    • 到临时文件的管道可能比重复覆盖目标文件(dos2unix,然后是iconv,然后是sed -i)更有效。
    【解决方案2】:

    你可以使用 awk,

    $ awk 'NR>2{sub(/,[^,]*$/,"",$0);print}' file
    1,1027.84
    2,1027.92
    3,1028
    4,1028.81
    

    sed -i '1,2d;s/,[^,]*$//' file
    
    • 1,2d; 删除前两行。
    • s/,[^,]*$// 删除剩余行中的最后一个逗号部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-01
      • 2022-09-27
      • 2011-04-01
      • 2010-09-25
      • 2020-06-25
      • 2012-05-14
      • 1970-01-01
      • 2011-11-20
      相关资源
      最近更新 更多