2

I have many txt files in a folder. Each file contains one line in this format;

8852 0.53451 0.55959 0.65494 0.36047

I would like to add, in the next line, a fixed number and the rest 4 columns copying from the original line, like so

8852 0.53451 0.55959 0.65494 0.36047

9997 0.53451 0.55959 0.65494 0.36047

So far I managed to add 9997 by the below command inside the folder

find *.txt -exec sh -c 'echo "9997" >> $0' {} \;

and managed to copy the rest 4 columns by

for files in .; do awk '{$1=""; print substr($0,2)}' *.txt;done

but it prints out in the output and not in the next line in each file.

I haven't managed to put them together yet and felt like I come so close but maybe in a wrong direction. I tried awk '{print "\n"$2,$3,$4,$5}'but it also didn't work.

Any help is appreciated! Thank you.

  • Are you trying to update the files in one directory or recursively update files in this directory and all directories under it? – Ed Morton Jul 3 at 22:27
  • @Ed in this directory and other directories next to it. sorry for late reply. thank you for your suggestions. – Pimpwhippa Jul 4 at 11:01
0

Given your comment that you want to update files in this directory and other directories next to it., lets assume you have a directory under which there are other directories under which there are the files you want to modify. This is how you'd do that after cd-ing to that top level directory:

find . -maxdepth 2 -mindepth 2 -exec awk -i inplace '{print} $1==8852{$1=9997; print}' {} +

The above uses GNU awk for "inplace" editing and GNU find for +. If you don't have GNU tools then, assuming your file names don't contain newlines:

tmp=$(mktemp)
while IFS= read -r file; do
    awk '{print} $1==8852{$1=9997; print}' "$file" > "$tmp" &&
    mv "$tmp" "$file"
done < <(find . -maxdepth 2 -mindepth 2) )
rm -f "$tmp"

If you don't want to change the timestamp on files that don't containing 8852 then:

tmp=$(mktemp)
while IFS= read -r file; do
    awk '$1==8852{f=1; exit} END{exit !f}' "$file" &&
    awk '{print} $1==8852{$1=9997; print}' "$file" > "$tmp" &&
    mv "$tmp" "$file"
done < <(find . -maxdepth 2 -mindepth 2) )
rm -f "$tmp"
  • 1
    thanks for the proper way to make it works. not a one liner finally! anyway, to update all other directories from the top level directory, I have to modify it further, as not all the directories has 8852 to start with. I'll try to figure that out. Thank you – Pimpwhippa Jul 5 at 12:52
  • I meant other directories have other numbers that's not 8852, but I also want to change them :) I think I really have to write a script for that e.g. directories with files that contain 26053 0.xxxxx 0.xxxxx 0.xxxxx 0.xxxxx also needs to add in the next line 9997 0.xxxxx 0.xxxxx 0.xxxxx 0.xxxxx – Pimpwhippa Jul 6 at 10:59
  • OK, feel free to ask a new question with more accurate/representative sample input/output if you have a question about how to do that. – Ed Morton Jul 6 at 11:02
  • 1
    yes, will figure out the overview of what I want and will see if I can do it myself first. thanks again. – Pimpwhippa Jul 6 at 11:06
2

I'd suggest awk '{print; $1 = 9997; print}'

$ echo '8852 0.53451 0.55959 0.65494 0.36047' | awk '{print; $1 = 9997; print}'
8852 0.53451 0.55959 0.65494 0.36047
9997 0.53451 0.55959 0.65494 0.36047

You mention applying the transformation to multiple files: you can do so either using a loop

for f in *.txt; do  awk '{print; $1 = 9997; print}' "$f"; done

or (recursively) using find

find . -name '*.txt' -exec awk '{print; $1 = 9997; print}' {} \;

however unless you have a recent version of GNU Awk with the -i inplace extension, the results will be concatenated and written to standard output.

  • yes I tried the one above, and the results are written to standard output. thank you for your proper answer. – Pimpwhippa Jul 4 at 11:10
-1

So you have many files and they have one line in the below format.

8852 0.53451 0.55959 0.65494 0.36047

Now you want to open the file and replace the first column with a value of your choice and leave the rest as it is, then append it to the next line.

8852 0.53451 0.55959 0.65494 0.36047

9997 0.53451 0.55959 0.65494 0.36047

If I get this question right, the below should work.

for file in ``find . -name "*.txt"``; do awk '{print "\n9997 "$2,$3,$4,$5}' $file >> $file; done

Get all the files in a folder, with awk read the file and take 2345 columns and for the first column add your value and append it to the same file.

Apologies if I got your question wrong.

  • 2
    Not only is this a bad idea due to parsing the output of ls but it's also going to give a bunch of errors iif there are any directories inside of the folder and if there are any files (or directories) with spaces in them. It would also perform the operateion on every file in that directory whether it's needed or not. You also don't need the double quotes in between the column parameters for awk as a space as a field separator can be denoted with a comma. – Nasir Riley Jul 3 at 21:08
  • I tried. it didn't work. maybe something to do with ls -1 as @Nasir mentioned? but yes you understand what I want correctly – Pimpwhippa Jul 3 at 21:10
  • 1
    @VigneshSP The downsides are that your command would break if any of the files contain spaces and/or if there are any files that contain the string txt that you don't want to operate on. A Google search will give plenty of examples of why parsing ls isn't a good idea starting with this one: unix.stackexchange.com/questions/128985/… – Nasir Riley Jul 3 at 21:31
  • 1
    Do not execute this code. So many bugs/anti-patterns in so little code - see mywiki.wooledge.org/Quotes, mywiki.wooledge.org/BashFAQ/001, pubs.opengroup.org/onlinepubs/9699919799, /xrat/V4_xcu_chap02.html#tag_23_02_06_03, unix.stackexchange.com/q/10241/133219, and I'm sure there's more... – Ed Morton Jul 3 at 22:26
  • 1
    oh thank you @Ed Morton – Pimpwhippa Jul 3 at 22:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.