1

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/$/;%/' %
0

3 Answers 3

1

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
6
  • 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, 2017 at 2:31
  • @thiagowfx thanks for pointing that out, will edit :)
    – Sundeep
    Apr 29, 2017 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? Apr 29, 2017 at 2:38
  • @speld_rwong check edit
    – Sundeep
    Apr 29, 2017 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' {} + Apr 29, 2017 at 2:48
1

With GNU awk:

LC_ALL=C find . -type f -exec gawk -i /usr/share/awk/inplace.awk '
  BEGINFILE {suffix = FILENAME; sub(/.*\//, "", suffix)}
  {print $0, suffix}' {} +

Beware that if there are several hard links of the same file, the name for each will be added (in no particular order) to each line of that file.

In any case, do not use -i inplace as gawk tries to load the inplace extension (as inplace or inplace.awk) from the current working directory first, where someone could have planted malware. The path of the inplace extension supplied with gawk may vary with the system, see the output of gawk 'BEGIN{print ENVIRON["AWKPATH"]}'

-1

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.

4
  • thiagowfx - I get this error with >>>>>> sed: -e expression #1, char 9: unknown option to `s' Apr 29, 2017 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, 2017 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, 2017 at 8:43
  • Great find! That's probably the reason why OP couldn't exec the above command.
    – thiagowfx
    Apr 29, 2017 at 8:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .