I want to add a line to my bash script (ubuntu 16) to add the filename to the end of every line in a file - that is every file in a folder and all files in all subfolders.

Filenames are alphanumeric with some special characters like -_.

For example:

Line in file filename_ghrut.txt before:

blah blah blah
blahblah blahblah

Line in file filename_ghrut.txt after:

blah blah blah filename_ghrut.txt
blahblah blahblah filename_ghrut.txt

I have searched around but most commands don't seem to work.

I want to run this on all files in all subfolders of a specific directory.

Big thanks.

I found this, but it doesn't quite work:

ls file{1..5}.txt|xargs -I% sed -i 's/$/;%/' %

Try this, using find and sed:

find /path/to/top_directory -type f -execdir sed -i -e "s/$/ {}/" {} \;

Replace /path/to/top_directory with the directory where the files you want to edit are.

  • thiagowfx - I get this error with >>>>>> sed: -e expression #1, char 9: unknown option to `s' – speld_rwong Apr 29 '17 at 2:35
  • What version of sed are you using? Is it GNU sed or BSD sed? It works with the default sed on my system (MacOS 10.12.4). – thiagowfx Apr 29 '17 at 2:41
  • 2
    @thiagowfx, GNU find passes the filename as ./file.name even with -execdir so the slash there clashes with the slash used as separator for the sed command. You'd need to use something like s%$% {}% with a character any of the filenames don't contain. – ilkkachu Apr 29 '17 at 8:43
  • Great find! That's probably the reason why OP couldn't exec the above command. – thiagowfx Apr 29 '17 at 8:50

With perl and find

find . -type f -exec perl -i -pe 's/$/ $ARGV/' {} +
  • s/$/ $ARGV/ add space and filename to end of each line
  • -i for inplace editing, use i.bkp if you want to retain a backup of original files
  • If your find doesn't support +, use \; instead
  • find . -type f will give list of all files in current directory
  • -exec allows to use a command to act upon all those files
  • Use find . -type f -name '*.txt' if you want to restrict to only files ending with .txt

Thanks @thiagowfx for pointing that above solution will add filename as ./file.txt, ./foo/file2.txt, etc

Use this to add only filename without any ./ etc

find . -type f -exec perl -i -pe 's/$/$ARGV=~s|.*\/| |r/e' {} +
  • $ARGV=~s|.*\/| |r will give filename with all characters upto / removed
  • 1
    Nice solution too! I would advise to use execdir instead of exec; this way, you get the basename of each file. For example, a.txt instead of ./dir/a.txt. – thiagowfx Apr 29 '17 at 2:31
  • @thiagowfx thanks for pointing that out, will edit :) – Sundeep Apr 29 '17 at 2:33
  • Sundeep - perl command works fine - but it adds the list of subfolders and filename e.g. blahblah /folder/folder/folder/folder/folder/filename.txt Any way to just add the filename without the directories? – speld_rwong Apr 29 '17 at 2:38
  • @speld_rwong check edit – Sundeep Apr 29 '17 at 2:40
  • 1
    Sundeep -- just added -i inplace and it works - THANKS >>>> find . -type f -exec perl -i -pe 's/$/$ARGV=~s|.*\/| |r/e' {} + – speld_rwong Apr 29 '17 at 2:48

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.